From d68cce067357353f200a700718a4914aec40db6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?REBUILD=20=E4=BC=81=E4=B8=9A=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= <42044143+getrebuild@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:27:59 +0800 Subject: [PATCH] be (#707) * be: tips * enh: h5NoKill * enh: session Keep 60s for H5 * enh: H5 session setMaxInactiveInterval * ImageMaker --------- Co-authored-by: devezhao --- .../rebuild/core/privileges/UserHelper.java | 91 +---------- .../java/com/rebuild/utils/ImageMaker.java | 145 ++++++++++++++++++ .../com/rebuild/web/OnlineSessionStore.java | 5 +- .../rebuild/web/RebuildWebInterceptor.java | 5 +- .../rebuild/web/user/signup/LoginAction.java | 56 ++++--- .../web/admin/integration/storage-qiniu.html | 7 +- .../web/admin/integration/submail.html | 10 +- src/main/resources/web/admin/system-cfg.html | 2 +- .../web/assets/js/admin/system-cfg.js | 5 + .../com/rebuild/utils/ImageMakerTest.java | 23 +++ 10 files changed, 232 insertions(+), 117 deletions(-) create mode 100644 src/main/java/com/rebuild/utils/ImageMaker.java create mode 100644 src/test/java/com/rebuild/utils/ImageMakerTest.java diff --git a/src/main/java/com/rebuild/core/privileges/UserHelper.java b/src/main/java/com/rebuild/core/privileges/UserHelper.java index ec2fe7032..f8b2a2eb1 100644 --- a/src/main/java/com/rebuild/core/privileges/UserHelper.java +++ b/src/main/java/com/rebuild/core/privileges/UserHelper.java @@ -24,21 +24,13 @@ import com.rebuild.core.privileges.bizz.Department; import com.rebuild.core.privileges.bizz.User; import com.rebuild.core.service.approval.FlowNode; import com.rebuild.core.support.RebuildConfiguration; -import com.rebuild.utils.CommonsUtils; +import com.rebuild.utils.ImageMaker; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.math.RandomUtils; -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.security.Principal; import java.util.ArrayList; import java.util.Arrays; @@ -305,95 +297,28 @@ public class UserHelper { return users; } - private static final Color[] RB_COLORS = new Color[]{ - new Color(66, 133, 244), - new Color(52, 168, 83), - new Color(251, 188, 5), - new Color(234, 67, 53), - new Color(155, 82, 222), - new Color(22, 168, 143), - }; - /** * 生成用户头像 * * @param name * @param forceMake * @return + * @see ImageMaker */ public static File generateAvatar(String name, boolean forceMake) { if (StringUtils.isBlank(name)) name = "RB"; - File avatar = RebuildConfiguration.getFileOfData("avatar-" + name + "29.jpg"); - if (avatar.exists()) { + File avatarFile = RebuildConfiguration.getFileOfData("avatar-" + name + "29.jpg"); + if (avatarFile.exists()) { if (forceMake) { - FileUtils.deleteQuietly(avatar); + FileUtils.deleteQuietly(avatarFile); } else { - return avatar; + return avatarFile; } } - if (name.length() > 2) name = name.substring(name.length() - 2); - name = name.toUpperCase(); - - BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); - Graphics2D g2d = (Graphics2D) bi.getGraphics(); - - g2d.setColor(RB_COLORS[RandomUtils.nextInt(RB_COLORS.length)]); - g2d.fillRect(0, 0, bi.getWidth(), bi.getHeight()); - - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); - - try { - final Font font = createFont(); - g2d.setFont(font); - g2d.setColor(Color.WHITE); - FontMetrics fontMetrics = g2d.getFontMetrics(font); - int x = fontMetrics.stringWidth(name); - g2d.drawString(name, (200 - x) / 2, 128); - g2d.setColor(new Color(0, 0, 0, 1)); - g2d.drawString("wbr", 0, 62); - g2d.dispose(); - - try (FileOutputStream fos = new FileOutputStream(avatar)) { - ImageIO.write(bi, "png", fos); - fos.flush(); - } - - } catch (Throwable ex) { - log.warn("Cannot make font-avatar : {}", name, ex); - - InputStream is = null; - try { - is = CommonsUtils.getStreamOfRes("/web" + DEFAULT_AVATAR); - - bi = ImageIO.read(is); - try (FileOutputStream fos = new FileOutputStream(avatar)) { - ImageIO.write(bi, "png", fos); - fos.flush(); - } - - } catch (IOException ignored) { - IOUtils.closeQuietly(is); - } - } - - return avatar; - } - - private static Font createFont() { - File fontFile = RebuildConfiguration.getFileOfData("SourceHanSansK-Regular.ttf"); - if (fontFile.exists()) { - try { - Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); - font = font.deriveFont((float) 81.0); - return font; - } catch (Throwable ex) { - log.warn("Cannot create Font: SourceHanSansK-Regular.ttf", ex); - } - } - // Use default - return new Font(Font.SERIF, Font.BOLD, (int) (float) 81.0); + ImageMaker.makeAvatar(name, avatarFile); + return avatarFile; } /** diff --git a/src/main/java/com/rebuild/utils/ImageMaker.java b/src/main/java/com/rebuild/utils/ImageMaker.java new file mode 100644 index 000000000..81352575e --- /dev/null +++ b/src/main/java/com/rebuild/utils/ImageMaker.java @@ -0,0 +1,145 @@ +package com.rebuild.utils; + +import com.rebuild.core.RebuildException; +import com.rebuild.core.privileges.UserHelper; +import com.rebuild.core.support.RebuildConfiguration; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.math.RandomUtils; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author Zixin + * @since 2023/1/8 + */ +@Slf4j +public class ImageMaker { + + // 颜色 + public static final Color[] RB_COLORS = new Color[]{ + new Color(66, 133, 244), + new Color(52, 168, 83), + new Color(251, 188, 5), + new Color(234, 67, 53), + new Color(155, 82, 222), + new Color(22, 168, 143), + }; + + /** + * 生成LOGO(效果不佳暂不用) + * + * @param text + * @param color + * @param dest + * @return + */ + @Deprecated + public static void makeLogo(String text, Color color, File dest) { + BufferedImage bi = new BufferedImage(300, 60, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = (Graphics2D) bi.getGraphics(); + g2d.setComposite(AlphaComposite.Clear); + g2d.fillRect(0, 0, bi.getWidth(), bi.getHeight()); + g2d.setComposite(AlphaComposite.SrcOver); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + Color textColor = color == null ? RB_COLORS[RandomUtils.nextInt(RB_COLORS.length)] : color; + + FileUtils.deleteQuietly(dest); + try { + final Font font = createFont(63f); + g2d.setFont(font); + g2d.setColor(textColor); + FontMetrics fontMetrics = g2d.getFontMetrics(font); + int x = fontMetrics.stringWidth(text); + g2d.drawString(text, (300 - x) / 2, 60 - 6); + + try (FileOutputStream fos = new FileOutputStream(dest)) { + ImageIO.write(bi, "png", fos); + fos.flush(); + } + + } catch (Throwable ex) { + throw new RebuildException("Cannot make logo", ex); + } + } + + /** + * 生成头像 + * + * @param name + * @param dest + */ + public static void makeAvatar(String name, File dest) { + if (name.length() > 2) name = name.substring(name.length() - 2); + name = name.toUpperCase(); + + BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = (Graphics2D) bi.getGraphics(); + + g2d.setColor(RB_COLORS[RandomUtils.nextInt(RB_COLORS.length)]); + g2d.fillRect(0, 0, bi.getWidth(), bi.getHeight()); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + + FileUtils.deleteQuietly(dest); + try { + final Font font = createFont(81f); + g2d.setFont(font); + g2d.setColor(Color.WHITE); + FontMetrics fontMetrics = g2d.getFontMetrics(font); + int x = fontMetrics.stringWidth(name); + g2d.drawString(name, (200 - x) / 2, 128); + g2d.setColor(new Color(0, 0, 0, 1)); + g2d.drawString("wbr", 0, 62); + g2d.dispose(); + + try (FileOutputStream fos = new FileOutputStream(dest)) { + ImageIO.write(bi, "png", fos); + fos.flush(); + } + + } catch (Throwable ex) { + log.warn("Cannot make font-avatar : {}", name, ex); + + InputStream is = null; + try { + is = CommonsUtils.getStreamOfRes("/web" + UserHelper.DEFAULT_AVATAR); + bi = ImageIO.read(is); + try (FileOutputStream fos = new FileOutputStream(dest)) { + ImageIO.write(bi, "png", fos); + fos.flush(); + } + + } catch (IOException ignored) { + IOUtils.closeQuietly(is); + } + } + } + + /** + * 获取字体 + * + * @return + */ + static Font createFont(float size) { + File fontFile = RebuildConfiguration.getFileOfData("SourceHanSansK-Regular.ttf"); + if (fontFile.exists()) { + try { + Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); + font = font.deriveFont(size); + return font; + } catch (Throwable ex) { + log.warn("Cannot create Font: SourceHanSansK-Regular.ttf", ex); + } + } + // Use default + return new Font(Font.SERIF, Font.BOLD, (int) size); + } +} diff --git a/src/main/java/com/rebuild/web/OnlineSessionStore.java b/src/main/java/com/rebuild/web/OnlineSessionStore.java index c1bad4697..c5b26ebce 100644 --- a/src/main/java/com/rebuild/web/OnlineSessionStore.java +++ b/src/main/java/com/rebuild/web/OnlineSessionStore.java @@ -107,14 +107,15 @@ public class OnlineSessionStore implements HttpSessionListener { /** * @param request + * @param h5NoKill */ - public void storeLoginSuccessed(HttpServletRequest request) { + public void storeLoginSuccessed(HttpServletRequest request, boolean h5NoKill) { HttpSession s = request.getSession(); Object loginUser = s.getAttribute(WebUtils.CURRENT_USER); Assert.notNull(loginUser, "No login user found in session!"); if (!RebuildConfiguration.getBool(ConfigurationItem.MultipleSessions)) { - HttpSession previous = getSession((ID) loginUser); + HttpSession previous = h5NoKill ? null : getSession((ID) loginUser); if (previous != null) { log.warn("Kill previous session : {} ({})", previous.getId(), loginUser); diff --git a/src/main/java/com/rebuild/web/RebuildWebInterceptor.java b/src/main/java/com/rebuild/web/RebuildWebInterceptor.java index c64402b9b..662d1b44c 100644 --- a/src/main/java/com/rebuild/web/RebuildWebInterceptor.java +++ b/src/main/java/com/rebuild/web/RebuildWebInterceptor.java @@ -176,7 +176,10 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { - // Notings + // v3.6 H5 session 时间 + if (AppUtils.isRbMobile(request)) { + request.getSession().setMaxInactiveInterval(60 * 5); + } } @Override diff --git a/src/main/java/com/rebuild/web/user/signup/LoginAction.java b/src/main/java/com/rebuild/web/user/signup/LoginAction.java index 61b74ae78..46f4804fe 100644 --- a/src/main/java/com/rebuild/web/user/signup/LoginAction.java +++ b/src/main/java/com/rebuild/web/user/signup/LoginAction.java @@ -59,6 +59,36 @@ public class LoginAction extends BaseController { protected static final String PREFIX_2FA = "2FA:"; protected static final String PREFIX_ALT = "ALT:"; + /** + * @param request + * @param response + * @param user + * @param autoLogin + * @return + */ + protected Integer loginSuccessed(HttpServletRequest request, HttpServletResponse response, ID user, boolean autoLogin) { + return loginSuccessed(request, response, user, autoLogin, false); + } + + /** + * @param request + * @param response + * @param user + * @return + */ + protected Map loginSuccessedH5(HttpServletRequest request, HttpServletResponse response, ID user) { + Map resMap = new HashMap<>(); + + Integer ed = loginSuccessed(request, response, user, false, true); + if (ed != null) resMap.put("passwdExpiredDays", ed); + + String authToken = AuthTokenManager.generateAccessToken(user); + resMap.put("authToken", authToken); + + request.getSession().invalidate(); + return resMap; + } + /** * 登录成功 * @@ -66,9 +96,10 @@ public class LoginAction extends BaseController { * @param response * @param user * @param autoLogin + * @param fromH5 * @return 密码过期时间(如有) */ - protected Integer loginSuccessed(HttpServletRequest request, HttpServletResponse response, ID user, boolean autoLogin) { + private Integer loginSuccessed(HttpServletRequest request, HttpServletResponse response, ID user, boolean autoLogin, boolean fromH5) { // 自动登录 if (autoLogin) { final String altToken = CodecUtils.randomCode(60); @@ -82,7 +113,7 @@ public class LoginAction extends BaseController { ServletUtils.setSessionAttribute(request, WebUtils.CURRENT_USER, user); ServletUtils.setSessionAttribute(request, SK_USER_THEME, KVStorage.getCustomValue("THEME." + user)); - Application.getSessionStore().storeLoginSuccessed(request); + Application.getSessionStore().storeLoginSuccessed(request, fromH5); // 头像缓存 ServletUtils.setSessionAttribute(request, UserAvatar.SK_DAVATAR, System.currentTimeMillis()); @@ -109,27 +140,8 @@ public class LoginAction extends BaseController { } /** - * 登录成功 H5 + * 登录日志 * - * @param request - * @param response - * @param user - * @return - */ - protected Map loginSuccessedH5(HttpServletRequest request, HttpServletResponse response, ID user) { - Map resMap = new HashMap<>(); - - Integer ed = loginSuccessed(request, response, user, false); - if (ed != null) resMap.put("passwdExpiredDays", ed); - - String authToken = AuthTokenManager.generateAccessToken(user); - resMap.put("authToken", authToken); - - request.getSession().invalidate(); - return resMap; - } - - /** * @param request * @param user */ diff --git a/src/main/resources/web/admin/integration/storage-qiniu.html b/src/main/resources/web/admin/integration/storage-qiniu.html index b46b4ed23..d95a6700f 100644 --- a/src/main/resources/web/admin/integration/storage-qiniu.html +++ b/src/main/resources/web/admin/integration/storage-qiniu.html @@ -28,11 +28,10 @@ [[${storageAccount == null ? bundle.L('未设置') : storageAccount[3]}]] - - [[${bundle.L('存储空间')}]] -

[[${bundle.L('存储空间变更需你自行迁移原有数据')}]]

+ [[${bundle.L('存储空间')}]] + + [[${storageAccount == null ? bundle.L('未设置') : storageAccount[2]}]] - [[${storageAccount == null ? bundle.L('未设置') : storageAccount[2]}]] [[${bundle.L('密钥 AK')}]] diff --git a/src/main/resources/web/admin/integration/submail.html b/src/main/resources/web/admin/integration/submail.html index d67872db9..68d0cc006 100644 --- a/src/main/resources/web/admin/integration/submail.html +++ b/src/main/resources/web/admin/integration/submail.html @@ -21,6 +21,9 @@ .smtp tr.smtp-show { display: table-row; } + .smtp td[data-id='MailAddr'] > p { + display: none; + } @@ -62,11 +65,10 @@ [[${mailAccount == null ? bundle.L('未设置') : mailAccount[1]}]] - - [[${bundle.L('发件人地址')}]] -

[[${bundle.L('地址域名需与 SUBMAIL 中配置的域名匹配')}]]

+ [[${bundle.L('发件人地址')}]] + + [[${mailAccount == null ? bundle.L('未设置') : mailAccount[2]}]] - [[${mailAccount == null ? bundle.L('未设置') : mailAccount[2]}]] [[${bundle.L('发件人名称')}]] diff --git a/src/main/resources/web/admin/system-cfg.html b/src/main/resources/web/admin/system-cfg.html index 99712c5a4..0b2a40eea 100644 --- a/src/main/resources/web/admin/system-cfg.html +++ b/src/main/resources/web/admin/system-cfg.html @@ -105,7 +105,7 @@ -

[[${bundle.L('请分别上传深色与白色 LOGO,透明背景,建议尺寸 300 × 60')}]]

+

[[${bundle.L('请分别上传深色与白色 LOGO,透明背景,建议尺寸 300 × 60')}]] 制作 LOGO

diff --git a/src/main/resources/web/assets/js/admin/system-cfg.js b/src/main/resources/web/assets/js/admin/system-cfg.js index 4b86f9026..5c73381db 100644 --- a/src/main/resources/web/assets/js/admin/system-cfg.js +++ b/src/main/resources/web/assets/js/admin/system-cfg.js @@ -191,6 +191,11 @@ const _toggleImage = function (el, init) { _$imgCurrent.find('>i').css('background-image', `url(${rb.baseUrl}/assets/img/s.gif)`) changeValue({ target: { name: _$imgCurrent.data('id'), value: '' } }) }) + $img + .find('.J_logo-gen') + .removeAttr('title') + .off('click') + .on('click', () => {}) } class DlgMM extends RbAlert { diff --git a/src/test/java/com/rebuild/utils/ImageMakerTest.java b/src/test/java/com/rebuild/utils/ImageMakerTest.java new file mode 100644 index 000000000..ce6e99a13 --- /dev/null +++ b/src/test/java/com/rebuild/utils/ImageMakerTest.java @@ -0,0 +1,23 @@ +package com.rebuild.utils; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; + +import java.io.File; + +/** + */ +class ImageMakerTest { + + @SuppressWarnings("deprecation") + @Test + void makeLogo() { + File tmp = new File(FileUtils.getTempDirectory(), "logo.png"); + ImageMaker.makeLogo("锐昉科技", null, tmp); + System.out.println(tmp); + } + + @Test + void makeAvatar() { + } +} \ No newline at end of file