update 更改包名为 org.dromara
update 更改文档地址为 plus-doc.dromara.org
已添加428个文件
已删除428个文件
已修改84个文件
| | |
| | | ## å¹³å°ç®ä» |
| | | |
| | | [](https://gitee.com/dromara/RuoYi-Vue-Plus) |
| | | [](https://github.com/dromara/RuoYi-Vue-Plus) |
| | | [](https://github.com/dromara/RuoYi-Vue-Plus) |
| | | [](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) |
| | | [](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) |
| | | <br> |
| | |
| | | > 项ç®ä»£ç ãææ¡£ å弿ºå
è´¹å¯åç¨ éµå¾ªå¼æºåè®®å¨é¡¹ç®ä¸ä¿ç弿ºåè®®æä»¶å³å¯<br> |
| | | æ´»å°èåå°è 为å
´è¶£è弿º 为å¦ä¹ è弿º ä¸ºè®©å¤§å®¶çæ£å¯ä»¥å¦å°ææ¯è弿º |
| | | |
| | | > ç³»ç»æ¼ç¤º: [ä¼ éé¨](https://javalionli.gitee.io/plus-doc/#/common/demo_system) |
| | | > ç³»ç»æ¼ç¤º: [ä¼ éé¨](https://plus-doc.dromara.org/#/common/demo_system) |
| | | |
| | | > å端项ç®å°å: [plus-ui](https://gitee.com/JavaLionLi/plus-ui) |
| | | |
| | |
| | | |
| | | | åè½ | æ¬æ¡æ¶ | RuoYi | |
| | | |-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| |
| | | | åç«¯é¡¹ç® | åºäºvue3-element-admin弿ºé¡¹ç®éå<br/>Vue3 + TS + ElementPlus | åºäºVue2/Vue3 + JS | |
| | | | åç«¯é¡¹ç® | éç¨ Vue3 + TS + ElementPlus éå | åºäºVue2/Vue3 + JS | |
| | | | å端项ç®ç»æ | éç¨æä»¶å + æ©å±å
å½¢å¼ ç»æè§£è¦ æäºæ©å± | 模åç¸äºæ³¨å
¥è¦å严éé¾ä»¥æ©å± | |
| | | | å端代ç 飿 ¼ | ä¸¥æ ¼éµå®Alibabaè§èä¸é¡¹ç®ç»ä¸é
ç½®çä»£ç æ ¼å¼å | 代ç 书åä¸å¸¸è§ç»æä¸åé
读éç¢å¤§ | |
| | | | Webå®¹å¨ | éç¨ Undertow åºäº XNIO ç髿§è½å®¹å¨ | éç¨ Tomcat | |
| | |
| | | | WebSocketåè®® | åºäº Spring å°è£
ç WebSocket åè®® æ©å±äºTokené´æä¸åå¸å¼ä¼è¯åæ¥ ä¸ååªæ¯åºäºåæºçåºç© | æ | |
| | | | åºåå | éç¨ Jackson Spring宿¹å
ç½®åºåå é è°±!!! | éç¨ fastjson bugjson è¿è¿é»å | |
| | | | åå¸å¼å¹ç | åèç¾å¢GTISé²éç³»ç»ç®åå®ç°(ç»èå¯çææ¡£) | æå¨ç¼å注解åºäºaopå®ç° | |
| | | | åå¸å¼é | éç¨ Lock4j åºå±åºäº Redisson | æ | |
| | | | åå¸å¼ä»»å¡è°åº¦ | éç¨ Xxl-Job å¤©çæ¯æåå¸å¼ ç»ä¸ç管çä¸å¿ | éç¨ Quartz åºäºæ°æ®åºéæ§è½å·® é群éè¦åå¾å¤é
ç½®ä¸æ¹é | |
| | | | æä»¶åå¨ | éç¨ Minio åå¸å¼æä»¶åå¨ å¤©çæ¯æå¤æºãå¤ç¡¬çãå¤åçãå¤å¯æ¬åå¨<br/>æ¯ææé管ç å®å
¨å¯é æä»¶å¯å å¯åå¨ | éç¨ æ¬æºæä»¶åå¨ æä»¶è£¸æ¼ æä¸¢å¤±æ³æ¼ 䏿¯æé群æåç¹æåº | |
| | | | äºåå¨ | éç¨ AWS S3 å议客æ·ç«¯ æ¯æ ä¸çãé¿éãè
¾è®¯ çä¸åæ¯æS3åè®®çåå®¶ | 䏿¯æ | |
| | |
| | | |
| | | ä½¿ç¨æ¡æ¶å请ä»ç»é
è¯»ææ¡£éç¹æ³¨æäºé¡¹ |
| | | <br> |
| | | >[åå§åé¡¹ç® å¿
ç](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/init) |
| | | >>[https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/init](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/init) |
| | | >[åå§åé¡¹ç® å¿
ç](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) |
| | | >>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) |
| | | > |
| | | >[䏿 ä¸è§é¢ å
¥é¨å¿
ç](https://javalionli.gitee.io/plus-doc/#/common/column) |
| | | >>[https://javalionli.gitee.io/plus-doc/#/common/column](https://javalionli.gitee.io/plus-doc/#/common/column) |
| | | >[䏿 ä¸è§é¢ å
¥é¨å¿
ç](https://plus-doc.dromara.org/#/common/column) |
| | | >>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column) |
| | | > |
| | | >[é¨ç½²é¡¹ç® å¿
ç](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/deploy) |
| | | >>[https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/deploy](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/quickstart/deploy) |
| | | >[é¨ç½²é¡¹ç® å¿
ç](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) |
| | | >>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) |
| | | > |
| | | >[åèææ¡£ Wiki](https://javalionli.gitee.io/plus-doc) |
| | | >>[https://javalionli.gitee.io/plus-doc](https://javalionli.gitee.io/plus-doc) |
| | | >[åèææ¡£ Wiki](https://plus-doc.dromara.org) |
| | | >>[https://plus-doc.dromara.org](https://plus-doc.dromara.org) |
| | | |
| | | ## è½¯ä»¶æ¶æå¾ |
| | | |
| | |
| | | |
| | | ## å¦ä½åä¸è´¡ç® |
| | | |
| | | [åä¸è´¡ç®çæ¹å¼ https://javalionli.gitee.io/plus-doc/#/common/contribution](https://javalionli.gitee.io/plus-doc/#/common/contribution) |
| | | [åä¸è´¡ç®çæ¹å¼ https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) |
| | | |
| | | ### å
¶ä» |
| | | |
| | |
| | | * GitHub å°å [RuoYi-Vue-Plus](https://github.com/dromara/RuoYi-Vue-Plus) |
| | | * å¾®æå¡ 忝 [RuoYi-Cloud-Plus](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus) |
| | | * åç«¯é¡¹ç® å°å [plus-ui](https://gitee.com/JavaLionLi/plus-ui) |
| | | * ç¨æ·æ©å±é¡¹ç® [æ©å±é¡¹ç®å表](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/extend-project/list) |
| | | * ç¨æ·æ©å±é¡¹ç® [æ©å±é¡¹ç®å表](https://plus-doc.dromara.org/#/ruoyi-vue-plus/extend-project/list) |
| | | |
| | | ## å ç¾¤ä¸æç® |
| | | >[å ç¾¤ä¸æç®](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/other/group_chat) |
| | | >>[https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/other/group_chat](https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/other/group_chat) |
| | | >[å ç¾¤ä¸æç®](https://plus-doc.dromara.org/#/ruoyi-vue-plus/other/group_chat) |
| | | >>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/other/group_chat](https://plus-doc.dromara.org/#/ruoyi-vue-plus/other/group_chat) |
| | | |
| | | ## æç®ä½è
|
| | | ä½è
为å
¼èå弿º,å¹³æ¶è¿éè¦å·¥ä½,妿叮å°äºæ¨å¯ä»¥è¯·ä½è
å个çé¥ |
| | | <img src="https://images.gitee.com/uploads/images/2022/0218/213734_b1b8197f_1766278.jpeg" width="300px" height="450px" /> |
| | | <img src="https://images.gitee.com/uploads/images/2021/0525/101713_3d18b119_1766278.jpeg" width="300px" height="450px" /> |
| | | <img src="https://foruda.gitee.com/images/1678975784848381069/d8661ed9_1766278.png" width="300px" height="450px" /> |
| | | <img src="https://foruda.gitee.com/images/1678975801230205215/6f96229d_1766278.png" width="300px" height="450px" /> |
| | | |
| | | ## æ¼ç¤ºå¾ä¾ |
| | | |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-vue-plus</artifactId> |
| | | <version>${revision}</version> |
| | | |
| | |
| | | |
| | | <!-- common çä¾èµé
ç½®--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-bom</artifactId> |
| | | <version>${revision}</version> |
| | | <type>pom</type> |
| | |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-system</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-job</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-generator</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-demo</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <artifactId>ruoyi-vue-plus</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-doc</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-system</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-job</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- 代ç çæ--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-generator</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- demo模å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-demo</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara; |
| | | |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | | import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; |
| | | |
| | | /** |
| | | * å¯å¨ç¨åº |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @SpringBootApplication |
| | | public class DromaraApplication { |
| | | |
| | | public static void main(String[] args) { |
| | | SpringApplication application = new SpringApplication(DromaraApplication.class); |
| | | application.setApplicationStartup(new BufferingApplicationStartup(2048)); |
| | | application.run(args); |
| | | System.out.println("(â¥â â¿â )ï¾ï¾ RuoYi-Vue-Pluså¯å¨æå á(´ڡ`á)ï¾"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara; |
| | | |
| | | import org.springframework.boot.builder.SpringApplicationBuilder; |
| | | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
| | | |
| | | /** |
| | | * web容å¨ä¸è¿è¡é¨ç½² |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class DromaraServletInitializer extends SpringBootServletInitializer { |
| | | |
| | | @Override |
| | | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { |
| | | return application.sources(DromaraApplication.class); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.controller; |
| | | |
| | | import cn.dev33.satoken.annotation.SaIgnore; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.domain.model.EmailLoginBody; |
| | | import org.dromara.common.core.domain.model.LoginBody; |
| | | import org.dromara.common.core.domain.model.RegisterBody; |
| | | import org.dromara.common.core.domain.model.SmsLoginBody; |
| | | import org.dromara.common.core.utils.MapstructUtils; |
| | | import org.dromara.common.core.utils.StreamUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | import org.dromara.system.domain.bo.SysTenantBo; |
| | | import org.dromara.system.domain.vo.SysTenantVo; |
| | | import org.dromara.system.service.ISysConfigService; |
| | | import org.dromara.system.service.ISysTenantService; |
| | | import org.dromara.web.domain.vo.LoginTenantVo; |
| | | import org.dromara.web.domain.vo.LoginVo; |
| | | import org.dromara.web.domain.vo.TenantListVo; |
| | | import org.dromara.web.service.SysLoginService; |
| | | import org.dromara.web.service.SysRegisterService; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.net.URL; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è®¤è¯ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SaIgnore |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/auth") |
| | | public class AuthController { |
| | | |
| | | private final SysLoginService loginService; |
| | | private final SysRegisterService registerService; |
| | | private final ISysConfigService configService; |
| | | private final ISysTenantService tenantService; |
| | | |
| | | /** |
| | | * ç»å½æ¹æ³ |
| | | * |
| | | * @param body ç»å½ä¿¡æ¯ |
| | | * @return ç»æ |
| | | */ |
| | | @PostMapping("/login") |
| | | public R<LoginVo> login(@Validated @RequestBody LoginBody body) { |
| | | LoginVo loginVo = new LoginVo(); |
| | | // çæä»¤ç |
| | | String token = loginService.login( |
| | | body.getTenantId(), |
| | | body.getUsername(), body.getPassword(), |
| | | body.getCode(), body.getUuid()); |
| | | loginVo.setToken(token); |
| | | return R.ok(loginVo); |
| | | } |
| | | |
| | | /** |
| | | * çä¿¡ç»å½ |
| | | * |
| | | * @param body ç»å½ä¿¡æ¯ |
| | | * @return ç»æ |
| | | */ |
| | | @PostMapping("/smsLogin") |
| | | public R<LoginVo> smsLogin(@Validated @RequestBody SmsLoginBody body) { |
| | | LoginVo loginVo = new LoginVo(); |
| | | // çæä»¤ç |
| | | String token = loginService.smsLogin(body.getTenantId(), body.getPhonenumber(), body.getSmsCode()); |
| | | loginVo.setToken(token); |
| | | return R.ok(loginVo); |
| | | } |
| | | |
| | | /** |
| | | * é®ä»¶ç»å½ |
| | | * |
| | | * @param body ç»å½ä¿¡æ¯ |
| | | * @return ç»æ |
| | | */ |
| | | @PostMapping("/emailLogin") |
| | | public R<LoginVo> emailLogin(@Validated @RequestBody EmailLoginBody body) { |
| | | LoginVo loginVo = new LoginVo(); |
| | | // çæä»¤ç |
| | | String token = loginService.emailLogin(body.getTenantId(), body.getEmail(), body.getEmailCode()); |
| | | loginVo.setToken(token); |
| | | return R.ok(loginVo); |
| | | } |
| | | |
| | | /** |
| | | * å°ç¨åºç»å½(示ä¾) |
| | | * |
| | | * @param xcxCode å°ç¨åºcode |
| | | * @return ç»æ |
| | | */ |
| | | @PostMapping("/xcxLogin") |
| | | public R<LoginVo> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { |
| | | LoginVo loginVo = new LoginVo(); |
| | | // çæä»¤ç |
| | | String token = loginService.xcxLogin(xcxCode); |
| | | loginVo.setToken(token); |
| | | return R.ok(loginVo); |
| | | } |
| | | |
| | | /** |
| | | * éåºç»å½ |
| | | */ |
| | | @PostMapping("/logout") |
| | | public R<Void> logout() { |
| | | loginService.logout(); |
| | | return R.ok("éåºæå"); |
| | | } |
| | | |
| | | /** |
| | | * ç¨æ·æ³¨å |
| | | */ |
| | | @PostMapping("/register") |
| | | public R<Void> register(@Validated @RequestBody RegisterBody user) { |
| | | if (!configService.selectRegisterEnabled(user.getTenantId())) { |
| | | return R.fail("å½åç³»ç»æ²¡æå¼å¯æ³¨ååè½ï¼"); |
| | | } |
| | | registerService.register(user); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * ç»å½é¡µé¢ç§æ·ä¸ææ¡ |
| | | * |
| | | * @return ç§æ·å表 |
| | | */ |
| | | @GetMapping("/tenant/list") |
| | | public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception { |
| | | List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo()); |
| | | List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class); |
| | | // è·ååå |
| | | String host = new URL(request.getRequestURL().toString()).getHost(); |
| | | // æ ¹æ®ååè¿è¡çé |
| | | List<TenantListVo> list = StreamUtils.filter(voList, vo -> StringUtils.equals(vo.getDomain(), host)); |
| | | // è¿å对象 |
| | | LoginTenantVo vo = new LoginTenantVo(); |
| | | vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList); |
| | | vo.setTenantEnabled(TenantHelper.isEnable()); |
| | | return R.ok(vo); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.controller; |
| | | |
| | | import cn.dev33.satoken.annotation.SaIgnore; |
| | | import cn.hutool.captcha.AbstractCaptcha; |
| | | import cn.hutool.captcha.generator.CodeGenerator; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import org.dromara.common.core.constant.Constants; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.core.utils.reflect.ReflectUtils; |
| | | import org.dromara.common.mail.config.properties.MailProperties; |
| | | import org.dromara.common.mail.utils.MailUtils; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.sms.config.properties.SmsProperties; |
| | | import org.dromara.common.sms.core.SmsTemplate; |
| | | import org.dromara.common.sms.entity.SmsResult; |
| | | import org.dromara.common.web.config.properties.CaptchaProperties; |
| | | import org.dromara.common.web.enums.CaptchaType; |
| | | import org.dromara.web.domain.vo.CaptchaVo; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.expression.Expression; |
| | | import org.springframework.expression.ExpressionParser; |
| | | import org.springframework.expression.spel.standard.SpelExpressionParser; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * éªè¯ç æä½å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SaIgnore |
| | | @Slf4j |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | public class CaptchaController { |
| | | |
| | | private final CaptchaProperties captchaProperties; |
| | | private final SmsProperties smsProperties; |
| | | private final MailProperties mailProperties; |
| | | |
| | | /** |
| | | * çä¿¡éªè¯ç |
| | | * |
| | | * @param phonenumber ç¨æ·ææºå· |
| | | */ |
| | | @GetMapping("/sms/code") |
| | | public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { |
| | | if (!smsProperties.getEnabled()) { |
| | | return R.fail("å½åç³»ç»æ²¡æå¼å¯çä¿¡åè½ï¼"); |
| | | } |
| | | String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; |
| | | String code = RandomUtil.randomNumbers(4); |
| | | RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); |
| | | // éªè¯ç 模æ¿id èªè¡å¤ç (æ¥æ°æ®åºæåæ»åå¯) |
| | | String templateId = ""; |
| | | Map<String, String> map = new HashMap<>(1); |
| | | map.put("code", code); |
| | | SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); |
| | | SmsResult result = smsTemplate.send(phonenumber, templateId, map); |
| | | if (!result.isSuccess()) { |
| | | log.error("éªè¯ç çä¿¡åéå¼å¸¸ => {}", result); |
| | | return R.fail(result.getMessage()); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * é®ç®±éªè¯ç |
| | | * |
| | | * @param email é®ç®± |
| | | */ |
| | | @GetMapping("/email/code") |
| | | public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { |
| | | if (!mailProperties.getEnabled()) { |
| | | return R.fail("å½åç³»ç»æ²¡æå¼å¯é®ç®±åè½ï¼"); |
| | | } |
| | | String key = GlobalConstants.CAPTCHA_CODE_KEY + email; |
| | | String code = RandomUtil.randomNumbers(4); |
| | | RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); |
| | | try { |
| | | MailUtils.sendText(email, "ç»å½éªè¯ç ", "æ¨æ¬æ¬¡éªè¯ç 为ï¼" + code + "ï¼æææ§ä¸º" + Constants.CAPTCHA_EXPIRATION + "åéï¼è¯·å°½å¿«å¡«åã"); |
| | | } catch (Exception e) { |
| | | log.error("éªè¯ç çä¿¡åéå¼å¸¸ => {}", e.getMessage()); |
| | | return R.fail(e.getMessage()); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * çæéªè¯ç |
| | | */ |
| | | @GetMapping("/code") |
| | | public R<CaptchaVo> getCode() { |
| | | CaptchaVo captchaVo = new CaptchaVo(); |
| | | boolean captchaEnabled = captchaProperties.getEnable(); |
| | | if (!captchaEnabled) { |
| | | captchaVo.setCaptchaEnabled(false); |
| | | return R.ok(captchaVo); |
| | | } |
| | | // ä¿åéªè¯ç ä¿¡æ¯ |
| | | String uuid = IdUtil.simpleUUID(); |
| | | String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; |
| | | // çæéªè¯ç |
| | | CaptchaType captchaType = captchaProperties.getType(); |
| | | boolean isMath = CaptchaType.MATH == captchaType; |
| | | Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); |
| | | CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); |
| | | AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); |
| | | captcha.setGenerator(codeGenerator); |
| | | captcha.createCode(); |
| | | String code = captcha.getCode(); |
| | | if (isMath) { |
| | | ExpressionParser parser = new SpelExpressionParser(); |
| | | Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); |
| | | code = exp.getValue(String.class); |
| | | } |
| | | RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); |
| | | captchaVo.setUuid(uuid); |
| | | captchaVo.setImg(captcha.getImageBase64()); |
| | | return R.ok(captchaVo); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.controller; |
| | | |
| | | import cn.dev33.satoken.annotation.SaIgnore; |
| | | import org.dromara.common.core.config.RuoYiConfig; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * é¦é¡µ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SaIgnore |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | public class IndexController { |
| | | |
| | | /** |
| | | * ç³»ç»åºç¡é
ç½® |
| | | */ |
| | | private final RuoYiConfig ruoyiConfig; |
| | | |
| | | /** |
| | | * 访é®é¦é¡µï¼æç¤ºè¯ |
| | | */ |
| | | @GetMapping("/") |
| | | public String index() { |
| | | return StringUtils.format("欢è¿ä½¿ç¨{}åå°ç®¡çæ¡æ¶ï¼å½åçæ¬ï¼v{}ï¼è¯·éè¿å端å°å访é®ã", ruoyiConfig.getName(), ruoyiConfig.getVersion()); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.domain.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * éªè¯ç ä¿¡æ¯ |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Data |
| | | public class CaptchaVo { |
| | | |
| | | /** |
| | | * æ¯å¦å¼å¯éªè¯ç |
| | | */ |
| | | private Boolean captchaEnabled = true; |
| | | |
| | | private String uuid; |
| | | |
| | | /** |
| | | * éªè¯ç å¾ç |
| | | */ |
| | | private String img; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.domain.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç»å½ç§æ·å¯¹è±¡ |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Data |
| | | public class LoginTenantVo { |
| | | |
| | | /** |
| | | * ç§æ·å¼å
³ |
| | | */ |
| | | private Boolean tenantEnabled; |
| | | |
| | | /** |
| | | * ç§æ·å¯¹è±¡å表 |
| | | */ |
| | | private List<TenantListVo> voList; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.domain.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ç»å½éªè¯ä¿¡æ¯ |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Data |
| | | public class LoginVo { |
| | | |
| | | private String token; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.domain.vo; |
| | | |
| | | import org.dromara.system.domain.vo.SysTenantVo; |
| | | import io.github.linpeilie.annotations.AutoMapper; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ç§æ·å表 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @AutoMapper(target = SysTenantVo.class) |
| | | public class TenantListVo { |
| | | |
| | | private String tenantId; |
| | | |
| | | private String companyName; |
| | | |
| | | private String domain; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.service; |
| | | |
| | | import cn.dev33.satoken.exception.NotLoginException; |
| | | import cn.dev33.satoken.secure.BCrypt; |
| | | import cn.dev33.satoken.stp.StpUtil; |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import org.dromara.common.core.constant.Constants; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.constant.TenantConstants; |
| | | import org.dromara.common.core.domain.dto.RoleDTO; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.domain.model.XcxLoginUser; |
| | | import org.dromara.common.core.enums.DeviceType; |
| | | import org.dromara.common.core.enums.LoginType; |
| | | import org.dromara.common.core.enums.TenantStatus; |
| | | import org.dromara.common.core.enums.UserStatus; |
| | | import org.dromara.common.core.exception.user.CaptchaException; |
| | | import org.dromara.common.core.exception.user.CaptchaExpireException; |
| | | import org.dromara.common.core.exception.user.UserException; |
| | | import org.dromara.common.core.utils.*; |
| | | import org.dromara.common.log.event.LogininforEvent; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import org.dromara.common.tenant.exception.TenantException; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | import org.dromara.common.web.config.properties.CaptchaProperties; |
| | | import org.dromara.system.domain.SysUser; |
| | | import org.dromara.system.domain.vo.SysTenantVo; |
| | | import org.dromara.system.domain.vo.SysUserVo; |
| | | import org.dromara.system.mapper.SysUserMapper; |
| | | import org.dromara.system.service.ISysPermissionService; |
| | | import org.dromara.system.service.ISysTenantService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.dromara.common.core.utils.*; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.function.Supplier; |
| | | |
| | | /** |
| | | * ç»å½æ ¡éªæ¹æ³ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Slf4j |
| | | @Service |
| | | public class SysLoginService { |
| | | |
| | | private final SysUserMapper userMapper; |
| | | private final CaptchaProperties captchaProperties; |
| | | private final ISysPermissionService permissionService; |
| | | private final ISysTenantService tenantService; |
| | | |
| | | @Value("${user.password.maxRetryCount}") |
| | | private Integer maxRetryCount; |
| | | |
| | | @Value("${user.password.lockTime}") |
| | | private Integer lockTime; |
| | | |
| | | /** |
| | | * ç»å½éªè¯ |
| | | * |
| | | * @param username ç¨æ·å |
| | | * @param password å¯ç |
| | | * @param code éªè¯ç |
| | | * @param uuid å¯ä¸æ è¯ |
| | | * @return ç»æ |
| | | */ |
| | | public String login(String tenantId, String username, String password, String code, String uuid) { |
| | | boolean captchaEnabled = captchaProperties.getEnable(); |
| | | // éªè¯ç å¼å
³ |
| | | if (captchaEnabled) { |
| | | validateCaptcha(tenantId, username, code, uuid); |
| | | } |
| | | // æ ¡éªç§æ· |
| | | checkTenant(tenantId); |
| | | |
| | | SysUserVo user = loadUserByUsername(tenantId, username); |
| | | checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | LoginUser loginUser = buildLoginUser(user); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.PC); |
| | | |
| | | recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | public String smsLogin(String tenantId, String phonenumber, String smsCode) { |
| | | // æ ¡éªç§æ· |
| | | checkTenant(tenantId); |
| | | // éè¿ææºå·æ¥æ¾ç¨æ· |
| | | SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); |
| | | |
| | | checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | LoginUser loginUser = buildLoginUser(user); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.APP); |
| | | |
| | | recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | public String emailLogin(String tenantId, String email, String emailCode) { |
| | | // æ ¡éªç§æ· |
| | | checkTenant(tenantId); |
| | | // éè¿ææºå·æ¥æ¾ç¨æ· |
| | | SysUserVo user = loadUserByEmail(tenantId, email); |
| | | |
| | | checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | LoginUser loginUser = buildLoginUser(user); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.APP); |
| | | |
| | | recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | |
| | | public String xcxLogin(String xcxCode) { |
| | | // xcxCode 为 å°ç¨åºè°ç¨ wx.login ææåè·å |
| | | // todo 以ä¸èªè¡å®ç° |
| | | // æ ¡éª appid + appsrcret + xcxCode è°ç¨ç»å½åè¯æ ¡éªæ¥å£ è·å session_key ä¸ openid |
| | | String openid = ""; |
| | | SysUserVo user = loadUserByOpenid(openid); |
| | | // æ ¡éªç§æ· |
| | | checkTenant(user.getTenantId()); |
| | | |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | XcxLoginUser loginUser = new XcxLoginUser(); |
| | | loginUser.setTenantId(user.getTenantId()); |
| | | loginUser.setUserId(user.getUserId()); |
| | | loginUser.setUsername(user.getUserName()); |
| | | loginUser.setUserType(user.getUserType()); |
| | | loginUser.setOpenid(openid); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.XCX); |
| | | |
| | | recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | /** |
| | | * éåºç»å½ |
| | | */ |
| | | public void logout() { |
| | | try { |
| | | LoginUser loginUser = LoginHelper.getLoginUser(); |
| | | if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { |
| | | // è¶
级管çå ç»åºæ¸
é¤å¨æç§æ· |
| | | TenantHelper.clearDynamic(); |
| | | } |
| | | StpUtil.logout(); |
| | | recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); |
| | | } catch (NotLoginException ignored) { |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è®°å½ç»å½ä¿¡æ¯ |
| | | * |
| | | * @param tenantId ç§æ·ID |
| | | * @param username ç¨æ·å |
| | | * @param status ç¶æ |
| | | * @param message æ¶æ¯å
容 |
| | | */ |
| | | private void recordLogininfor(String tenantId, String username, String status, String message) { |
| | | LogininforEvent logininforEvent = new LogininforEvent(); |
| | | logininforEvent.setTenantId(tenantId); |
| | | logininforEvent.setUsername(username); |
| | | logininforEvent.setStatus(status); |
| | | logininforEvent.setMessage(message); |
| | | logininforEvent.setRequest(ServletUtils.getRequest()); |
| | | SpringUtils.context().publishEvent(logininforEvent); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªçä¿¡éªè¯ç |
| | | */ |
| | | private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { |
| | | String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); |
| | | if (StringUtils.isBlank(code)) { |
| | | recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | return code.equals(smsCode); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªé®ç®±éªè¯ç |
| | | */ |
| | | private boolean validateEmailCode(String tenantId, String email, String emailCode) { |
| | | String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); |
| | | if (StringUtils.isBlank(code)) { |
| | | recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | return code.equals(emailCode); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªéªè¯ç |
| | | * |
| | | * @param username ç¨æ·å |
| | | * @param code éªè¯ç |
| | | * @param uuid å¯ä¸æ è¯ |
| | | */ |
| | | public void validateCaptcha(String tenantId, String username, String code, String uuid) { |
| | | String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); |
| | | String captcha = RedisUtils.getCacheObject(verifyKey); |
| | | RedisUtils.deleteObject(verifyKey); |
| | | if (captcha == null) { |
| | | recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | if (!code.equalsIgnoreCase(captcha)) { |
| | | recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); |
| | | throw new CaptchaException(); |
| | | } |
| | | } |
| | | |
| | | private SysUserVo loadUserByUsername(String tenantId, String username) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getUserName, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getUserName, username)); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", username); |
| | | throw new UserException("user.not.exists", username); |
| | | } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被åç¨.", username); |
| | | throw new UserException("user.blocked", username); |
| | | } |
| | | if (TenantHelper.isEnable()) { |
| | | return userMapper.selectTenantUserByUserName(username, tenantId); |
| | | } |
| | | return userMapper.selectUserByUserName(username); |
| | | } |
| | | |
| | | private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getPhonenumber, phonenumber)); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", phonenumber); |
| | | throw new UserException("user.not.exists", phonenumber); |
| | | } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被åç¨.", phonenumber); |
| | | throw new UserException("user.blocked", phonenumber); |
| | | } |
| | | if (TenantHelper.isEnable()) { |
| | | return userMapper.selectTenantUserByPhonenumber(phonenumber, tenantId); |
| | | } |
| | | return userMapper.selectUserByPhonenumber(phonenumber); |
| | | } |
| | | |
| | | private SysUserVo loadUserByEmail(String tenantId, String email) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getEmail, email)); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", email); |
| | | throw new UserException("user.not.exists", email); |
| | | } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被åç¨.", email); |
| | | throw new UserException("user.blocked", email); |
| | | } |
| | | if (TenantHelper.isEnable()) { |
| | | return userMapper.selectTenantUserByEmail(email, tenantId); |
| | | } |
| | | return userMapper.selectUserByEmail(email); |
| | | } |
| | | |
| | | private SysUserVo loadUserByOpenid(String openid) { |
| | | // ä½¿ç¨ openid æ¥è¯¢ç»å®ç¨æ· 妿ªç»å®ç¨æ· åæ ¹æ®ä¸å¡èªè¡å¤ç ä¾å¦ å建é»è®¤ç¨æ· |
| | | // todo èªè¡å®ç° userService.selectUserByOpenid(openid); |
| | | SysUserVo user = new SysUserVo(); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", openid); |
| | | // todo ç¨æ·ä¸åå¨ ä¸å¡é»è¾èªè¡å®ç° |
| | | } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被åç¨.", openid); |
| | | // todo ç¨æ·å·²è¢«åç¨ ä¸å¡é»è¾èªè¡å®ç° |
| | | } |
| | | return user; |
| | | } |
| | | |
| | | /** |
| | | * æå»ºç»å½ç¨æ· |
| | | */ |
| | | private LoginUser buildLoginUser(SysUserVo user) { |
| | | LoginUser loginUser = new LoginUser(); |
| | | loginUser.setTenantId(user.getTenantId()); |
| | | loginUser.setUserId(user.getUserId()); |
| | | loginUser.setDeptId(user.getDeptId()); |
| | | loginUser.setUsername(user.getUserName()); |
| | | loginUser.setUserType(user.getUserType()); |
| | | loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); |
| | | loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); |
| | | loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); |
| | | List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); |
| | | loginUser.setRoles(roles); |
| | | return loginUser; |
| | | } |
| | | |
| | | /** |
| | | * è®°å½ç»å½ä¿¡æ¯ |
| | | * |
| | | * @param userId ç¨æ·ID |
| | | */ |
| | | public void recordLoginInfo(Long userId) { |
| | | SysUser sysUser = new SysUser(); |
| | | sysUser.setUserId(userId); |
| | | sysUser.setLoginIp(ServletUtils.getClientIP()); |
| | | sysUser.setLoginDate(DateUtils.getNowDate()); |
| | | sysUser.setUpdateBy(userId); |
| | | userMapper.updateById(sysUser); |
| | | } |
| | | |
| | | /** |
| | | * ç»å½æ ¡éª |
| | | */ |
| | | private void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { |
| | | String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; |
| | | String loginFail = Constants.LOGIN_FAIL; |
| | | |
| | | // è·åç¨æ·ç»å½é误次æ°(å¯èªå®ä¹éå¶çç¥ ä¾å¦: key + username + ip) |
| | | Integer errorNumber = RedisUtils.getCacheObject(errorKey); |
| | | // é宿¶é´å
ç»å½ åè¸¢åº |
| | | if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) { |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } |
| | | |
| | | if (supplier.get()) { |
| | | // æ¯å¦ç¬¬ä¸æ¬¡ |
| | | errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; |
| | | // è¾¾å°è§å®éè¯¯æ¬¡æ° åéå®ç»å½ |
| | | if (errorNumber.equals(maxRetryCount)) { |
| | | RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } else { |
| | | // æªè¾¾å°è§å®éè¯¯æ¬¡æ° åéå¢ |
| | | RedisUtils.setCacheObject(errorKey, errorNumber); |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); |
| | | throw new UserException(loginType.getRetryLimitCount(), errorNumber); |
| | | } |
| | | } |
| | | |
| | | // ç»å½æå æ¸
空éè¯¯æ¬¡æ° |
| | | RedisUtils.deleteObject(errorKey); |
| | | } |
| | | |
| | | private void checkTenant(String tenantId) { |
| | | if (!TenantHelper.isEnable()) { |
| | | return; |
| | | } |
| | | if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { |
| | | return; |
| | | } |
| | | SysTenantVo tenant = tenantService.queryByTenantId(tenantId); |
| | | if (ObjectUtil.isNull(tenant)) { |
| | | log.info("ç»å½ç§æ·ï¼{} ä¸åå¨.", tenantId); |
| | | throw new TenantException("tenant.not.exists"); |
| | | } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { |
| | | log.info("ç»å½ç§æ·ï¼{} 已被åç¨.", tenantId); |
| | | throw new TenantException("tenant.blocked"); |
| | | } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) |
| | | && new Date().after(tenant.getExpireTime())) { |
| | | log.info("ç»å½ç§æ·ï¼{} å·²è¶
è¿æææ.", tenantId); |
| | | throw new TenantException("tenant.expired"); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.web.service; |
| | | |
| | | import cn.dev33.satoken.secure.BCrypt; |
| | | import org.dromara.common.core.constant.Constants; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.domain.model.RegisterBody; |
| | | import org.dromara.common.core.enums.UserType; |
| | | import org.dromara.common.core.exception.user.CaptchaException; |
| | | import org.dromara.common.core.exception.user.CaptchaExpireException; |
| | | import org.dromara.common.core.exception.user.UserException; |
| | | import org.dromara.common.core.utils.MessageUtils; |
| | | import org.dromara.common.core.utils.ServletUtils; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.log.event.LogininforEvent; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.web.config.properties.CaptchaProperties; |
| | | import org.dromara.system.domain.bo.SysUserBo; |
| | | import org.dromara.system.service.ISysUserService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | | * æ³¨åæ ¡éªæ¹æ³ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Service |
| | | public class SysRegisterService { |
| | | |
| | | private final ISysUserService userService; |
| | | private final CaptchaProperties captchaProperties; |
| | | |
| | | /** |
| | | * 注å |
| | | */ |
| | | public void register(RegisterBody registerBody) { |
| | | String tenantId = registerBody.getTenantId(); |
| | | String username = registerBody.getUsername(); |
| | | String password = registerBody.getPassword(); |
| | | // æ ¡éªç¨æ·ç±»åæ¯å¦åå¨ |
| | | String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); |
| | | |
| | | boolean captchaEnabled = captchaProperties.getEnable(); |
| | | // éªè¯ç å¼å
³ |
| | | if (captchaEnabled) { |
| | | validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); |
| | | } |
| | | SysUserBo sysUser = new SysUserBo(); |
| | | sysUser.setUserName(username); |
| | | sysUser.setNickName(username); |
| | | sysUser.setPassword(BCrypt.hashpw(password)); |
| | | sysUser.setUserType(userType); |
| | | |
| | | if (!userService.checkUserNameUnique(sysUser)) { |
| | | throw new UserException("user.register.save.error", username); |
| | | } |
| | | boolean regFlag = userService.registerUser(sysUser, tenantId); |
| | | if (!regFlag) { |
| | | throw new UserException("user.register.error"); |
| | | } |
| | | recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªéªè¯ç |
| | | * |
| | | * @param username ç¨æ·å |
| | | * @param code éªè¯ç |
| | | * @param uuid å¯ä¸æ è¯ |
| | | */ |
| | | public void validateCaptcha(String tenantId, String username, String code, String uuid) { |
| | | String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); |
| | | String captcha = RedisUtils.getCacheObject(verifyKey); |
| | | RedisUtils.deleteObject(verifyKey); |
| | | if (captcha == null) { |
| | | recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | if (!code.equalsIgnoreCase(captcha)) { |
| | | recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error")); |
| | | throw new CaptchaException(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è®°å½ç»å½ä¿¡æ¯ |
| | | * |
| | | * @param tenantId ç§æ·ID |
| | | * @param username ç¨æ·å |
| | | * @param status ç¶æ |
| | | * @param message æ¶æ¯å
容 |
| | | * @return |
| | | */ |
| | | private void recordLogininfor(String tenantId, String username, String status, String message) { |
| | | LogininforEvent logininforEvent = new LogininforEvent(); |
| | | logininforEvent.setTenantId(tenantId); |
| | | logininforEvent.setUsername(username); |
| | | logininforEvent.setStatus(status); |
| | | logininforEvent.setMessage(message); |
| | | logininforEvent.setRequest(ServletUtils.getRequest()); |
| | | SpringUtils.context().publishEvent(logininforEvent); |
| | | } |
| | | |
| | | } |
| | |
| | | # çæ¬ |
| | | version: ${revision} |
| | | # çæå¹´ä»½ |
| | | copyrightYear: 2022 |
| | | copyrightYear: 2023 |
| | | # å®ä¾æ¼ç¤ºå¼å
³ |
| | | demoEnabled: true |
| | | # è·åipå°åå¼å
³ |
| | |
| | | # æ¥å¿é
ç½® |
| | | logging: |
| | | level: |
| | | com.ruoyi: @logging.level@ |
| | | org.dromara: @logging.level@ |
| | | org.springframework: warn |
| | | config: classpath:logback.xml |
| | | |
| | |
| | | mybatis-plus: |
| | | # 䏿¯æå¤å
, 妿éè¦å¯å¨æ³¨è§£é
ç½® æ æåæ«å
ç级 |
| | | # ä¾å¦ com.**.**.mapper |
| | | mapperPackage: com.ruoyi.**.mapper |
| | | mapperPackage: org.dromara.**.mapper |
| | | # 对åºç XML æä»¶ä½ç½® |
| | | mapperLocations: classpath*:mapper/**/*Mapper.xml |
| | | # å®ä½æ«æï¼å¤ä¸ªpackageç¨éå·æè
åå·åé |
| | | typeAliasesPackage: com.ruoyi.**.domain |
| | | typeAliasesPackage: org.dromara.**.domain |
| | | # å¯å¨æ¶æ¯å¦æ£æ¥ MyBatis XML æä»¶çåå¨ï¼é»è®¤ä¸æ£æ¥ |
| | | checkConfigLocation: false |
| | | configuration: |
| | |
| | | # æè¿° |
| | | description: 'æè¿°ï¼ç¨äºç®¡çé墿ä¸å
¬å¸ç人åä¿¡æ¯,å
·ä½å
æ¬XXX,XXX模å...' |
| | | # çæ¬ |
| | | version: 'çæ¬å·: ${ruoyi-vue-plus.version}' |
| | | version: 'çæ¬å·: ${ruoyi.version}' |
| | | # ä½è
ä¿¡æ¯ |
| | | contact: |
| | | name: Lion Li |
| | |
| | | #è¿éå®ä¹äºä¸¤ä¸ªåç»ï¼å¯å®ä¹å¤ä¸ªï¼ä¹å¯ä»¥ä¸å®ä¹ |
| | | group-configs: |
| | | - group: 1.æ¼ç¤ºæ¨¡å |
| | | packages-to-scan: com.ruoyi.demo |
| | | packages-to-scan: org.dromara.demo |
| | | - group: 2.éç¨æ¨¡å |
| | | packages-to-scan: com.ruoyi.web |
| | | packages-to-scan: org.dromara.web |
| | | - group: 3.ç³»ç»æ¨¡å |
| | | packages-to-scan: com.ruoyi.system |
| | | packages-to-scan: org.dromara.system |
| | | - group: 4.代ç çææ¨¡å |
| | | packages-to-scan: com.ruoyi.generator |
| | | packages-to-scan: org.dromara.generator |
| | | |
| | | # 鲿¢XSSæ»å» |
| | | xss: |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.test; |
| | | |
| | | import org.junit.jupiter.api.Assertions; |
| | | import org.junit.jupiter.api.DisplayName; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | /** |
| | | * æè¨åå
æµè¯æ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @DisplayName("æè¨åå
æµè¯æ¡ä¾") |
| | | public class AssertUnitTest { |
| | | |
| | | @DisplayName("æµè¯ assertEquals æ¹æ³") |
| | | @Test |
| | | public void testAssertEquals() { |
| | | Assertions.assertEquals("666", new String("666")); |
| | | Assertions.assertNotEquals("666", new String("666")); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ assertSame æ¹æ³") |
| | | @Test |
| | | public void testAssertSame() { |
| | | Object obj = new Object(); |
| | | Object obj1 = obj; |
| | | Assertions.assertSame(obj, obj1); |
| | | Assertions.assertNotSame(obj, obj1); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ assertTrue æ¹æ³") |
| | | @Test |
| | | public void testAssertTrue() { |
| | | Assertions.assertTrue(true); |
| | | Assertions.assertFalse(true); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ assertNull æ¹æ³") |
| | | @Test |
| | | public void testAssertNull() { |
| | | Assertions.assertNull(null); |
| | | Assertions.assertNotNull(null); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.test; |
| | | |
| | | import org.dromara.common.core.config.RuoYiConfig; |
| | | import org.junit.jupiter.api.*; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.context.SpringBootTest; |
| | | |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * åå
æµè¯æ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SpringBootTest // æ¤æ³¨è§£åªè½å¨ springboot 主å
ä¸ä½¿ç¨ éå
å« main æ¹æ³ä¸ yml é
ç½®æä»¶ |
| | | @DisplayName("åå
æµè¯æ¡ä¾") |
| | | public class DemoUnitTest { |
| | | |
| | | @Autowired |
| | | private RuoYiConfig ruoYiConfig; |
| | | |
| | | @DisplayName("æµè¯ @SpringBootTest @Test @DisplayName 注解") |
| | | @Test |
| | | public void testTest() { |
| | | System.out.println(ruoYiConfig); |
| | | } |
| | | |
| | | @Disabled |
| | | @DisplayName("æµè¯ @Disabled 注解") |
| | | @Test |
| | | public void testDisabled() { |
| | | System.out.println(ruoYiConfig); |
| | | } |
| | | |
| | | @Timeout(value = 2L, unit = TimeUnit.SECONDS) |
| | | @DisplayName("æµè¯ @Timeout 注解") |
| | | @Test |
| | | public void testTimeout() throws InterruptedException { |
| | | Thread.sleep(3000); |
| | | System.out.println(ruoYiConfig); |
| | | } |
| | | |
| | | |
| | | @DisplayName("æµè¯ @RepeatedTest 注解") |
| | | @RepeatedTest(3) |
| | | public void testRepeatedTest() { |
| | | System.out.println(666); |
| | | } |
| | | |
| | | @BeforeAll |
| | | public static void testBeforeAll() { |
| | | System.out.println("@BeforeAll =================="); |
| | | } |
| | | |
| | | @BeforeEach |
| | | public void testBeforeEach() { |
| | | System.out.println("@BeforeEach =================="); |
| | | } |
| | | |
| | | @AfterEach |
| | | public void testAfterEach() { |
| | | System.out.println("@AfterEach =================="); |
| | | } |
| | | |
| | | @AfterAll |
| | | public static void testAfterAll() { |
| | | System.out.println("@AfterAll =================="); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.test; |
| | | |
| | | import org.dromara.common.core.enums.UserType; |
| | | import org.junit.jupiter.api.AfterEach; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.DisplayName; |
| | | import org.junit.jupiter.params.ParameterizedTest; |
| | | import org.junit.jupiter.params.provider.EnumSource; |
| | | import org.junit.jupiter.params.provider.MethodSource; |
| | | import org.junit.jupiter.params.provider.NullSource; |
| | | import org.junit.jupiter.params.provider.ValueSource; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.stream.Stream; |
| | | |
| | | /** |
| | | * 另忰åå
æµè¯æ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @DisplayName("另忰åå
æµè¯æ¡ä¾") |
| | | public class ParamUnitTest { |
| | | |
| | | @DisplayName("æµè¯ @ValueSource 注解") |
| | | @ParameterizedTest |
| | | @ValueSource(strings = {"t1", "t2", "t3"}) |
| | | public void testValueSource(String str) { |
| | | System.out.println(str); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ @NullSource 注解") |
| | | @ParameterizedTest |
| | | @NullSource |
| | | public void testNullSource(String str) { |
| | | System.out.println(str); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ @EnumSource 注解") |
| | | @ParameterizedTest |
| | | @EnumSource(UserType.class) |
| | | public void testEnumSource(UserType type) { |
| | | System.out.println(type.getUserType()); |
| | | } |
| | | |
| | | @DisplayName("æµè¯ @MethodSource 注解") |
| | | @ParameterizedTest |
| | | @MethodSource("getParam") |
| | | public void testMethodSource(String str) { |
| | | System.out.println(str); |
| | | } |
| | | |
| | | public static Stream<String> getParam() { |
| | | List<String> list = new ArrayList<>(); |
| | | list.add("t1"); |
| | | list.add("t2"); |
| | | list.add("t3"); |
| | | return list.stream(); |
| | | } |
| | | |
| | | @BeforeEach |
| | | public void testBeforeEach() { |
| | | System.out.println("@BeforeEach =================="); |
| | | } |
| | | |
| | | @AfterEach |
| | | public void testAfterEach() { |
| | | System.out.println("@AfterEach =================="); |
| | | } |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.test; |
| | | |
| | | import org.junit.jupiter.api.*; |
| | | import org.springframework.boot.test.context.SpringBootTest; |
| | | |
| | | /** |
| | | * æ ç¾åå
æµè¯æ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SpringBootTest |
| | | @DisplayName("æ ç¾åå
æµè¯æ¡ä¾") |
| | | public class TagUnitTest { |
| | | |
| | | @Tag("dev") |
| | | @DisplayName("æµè¯ @Tag dev") |
| | | @Test |
| | | public void testTagDev() { |
| | | System.out.println("dev"); |
| | | } |
| | | |
| | | @Tag("prod") |
| | | @DisplayName("æµè¯ @Tag prod") |
| | | @Test |
| | | public void testTagProd() { |
| | | System.out.println("prod"); |
| | | } |
| | | |
| | | @Tag("local") |
| | | @DisplayName("æµè¯ @Tag local") |
| | | @Test |
| | | public void testTagLocal() { |
| | | System.out.println("local"); |
| | | } |
| | | |
| | | @Tag("exclude") |
| | | @DisplayName("æµè¯ @Tag exclude") |
| | | @Test |
| | | public void testTagExclude() { |
| | | System.out.println("exclude"); |
| | | } |
| | | |
| | | @BeforeEach |
| | | public void testBeforeEach() { |
| | | System.out.println("@BeforeEach =================="); |
| | | } |
| | | |
| | | @AfterEach |
| | | public void testAfterEach() { |
| | | System.out.println("@AfterEach =================="); |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <artifactId>ruoyi-vue-plus</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-bom</artifactId> |
| | | <version>${revision}</version> |
| | | <packaging>pom</packaging> |
| | |
| | | <dependencies> |
| | | <!-- æ ¸å¿æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- æ¥å£æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-doc</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- excel --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-excel</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- å¹ç --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-idempotent</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- è°åº¦æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-job</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- æ¥å¿è®°å½ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-log</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- é®ä»¶æå¡ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-mail</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- æ°æ®åºæå¡ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-mybatis</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- OSS --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-oss</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- éæµ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-ratelimiter</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ç¼åæå¡ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- satoken --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-satoken</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- å®å
¨æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-security</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ç信模å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-sms</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- webæå¡ --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-web</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ç¿»è¯æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-translation</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- è±ææ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-sensitive</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- åºå忍¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- æ°æ®åºå è§£å¯æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-encrypt</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ç§æ·æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-tenant</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- WebSocket模å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-websocket</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config; |
| | | |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.EnableAspectJAutoProxy; |
| | | |
| | | /** |
| | | * ç¨åºæ³¨è§£é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | // 表示éè¿aopæ¡æ¶æ´é²è¯¥ä»£ç对象,AopContextè½å¤è®¿é® |
| | | @EnableAspectJAutoProxy(exposeProxy = true) |
| | | public class ApplicationConfig { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.scheduling.annotation.AsyncConfigurer; |
| | | import org.springframework.scheduling.annotation.EnableAsync; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.Executor; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | |
| | | /** |
| | | * 弿¥é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @EnableAsync(proxyTargetClass = true) |
| | | @AutoConfiguration |
| | | public class AsyncConfig implements AsyncConfigurer { |
| | | |
| | | @Autowired |
| | | @Qualifier("scheduledExecutorService") |
| | | private ScheduledExecutorService scheduledExecutorService; |
| | | |
| | | /** |
| | | * èªå®ä¹ @Async 注解使ç¨ç³»ç»çº¿ç¨æ± |
| | | */ |
| | | @Override |
| | | public Executor getAsyncExecutor() { |
| | | return scheduledExecutorService; |
| | | } |
| | | |
| | | /** |
| | | * 弿¥æ§è¡å¼å¸¸å¤ç |
| | | */ |
| | | @Override |
| | | public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { |
| | | return (throwable, method, objects) -> { |
| | | throwable.printStackTrace(); |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("Exception message - ").append(throwable.getMessage()) |
| | | .append(", Method name - ").append(method.getName()); |
| | | if (ArrayUtil.isNotEmpty(objects)) { |
| | | sb.append(", Parameter value - ").append(Arrays.toString(objects)); |
| | | } |
| | | throw new ServiceException(sb.toString()); |
| | | }; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config; |
| | | |
| | | import lombok.Data; |
| | | import lombok.Getter; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 读å项ç®ç¸å
³é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | @Component |
| | | @ConfigurationProperties(prefix = "ruoyi") |
| | | public class RuoYiConfig { |
| | | |
| | | /** |
| | | * 项ç®åç§° |
| | | */ |
| | | private String name; |
| | | |
| | | /** |
| | | * çæ¬ |
| | | */ |
| | | private String version; |
| | | |
| | | /** |
| | | * çæå¹´ä»½ |
| | | */ |
| | | private String copyrightYear; |
| | | |
| | | /** |
| | | * å®ä¾æ¼ç¤ºå¼å
³ |
| | | */ |
| | | private boolean demoEnabled; |
| | | |
| | | /** |
| | | * è·åå°åå¼å
³ |
| | | */ |
| | | @Getter |
| | | private static boolean addressEnabled; |
| | | |
| | | public void setAddressEnabled(boolean addressEnabled) { |
| | | RuoYiConfig.addressEnabled = addressEnabled; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config; |
| | | |
| | | import org.dromara.common.core.config.properties.ThreadPoolProperties; |
| | | import org.dromara.common.core.utils.Threads; |
| | | import org.apache.commons.lang3.concurrent.BasicThreadFactory; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.ScheduledThreadPoolExecutor; |
| | | import java.util.concurrent.ThreadPoolExecutor; |
| | | |
| | | /** |
| | | * çº¿ç¨æ± é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | **/ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(ThreadPoolProperties.class) |
| | | public class ThreadPoolConfig { |
| | | |
| | | /** |
| | | * æ ¸å¿çº¿ç¨æ° = cpu æ ¸å¿æ° + 1 |
| | | */ |
| | | private final int core = Runtime.getRuntime().availableProcessors() + 1; |
| | | |
| | | @Bean(name = "threadPoolTaskExecutor") |
| | | @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") |
| | | public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { |
| | | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| | | executor.setCorePoolSize(core); |
| | | executor.setMaxPoolSize(core * 2); |
| | | executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); |
| | | executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); |
| | | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| | | return executor; |
| | | } |
| | | |
| | | /** |
| | | * æ§è¡å¨ææ§æå®æ¶ä»»å¡ |
| | | */ |
| | | @Bean(name = "scheduledExecutorService") |
| | | protected ScheduledExecutorService scheduledExecutorService() { |
| | | return new ScheduledThreadPoolExecutor(core, |
| | | new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), |
| | | new ThreadPoolExecutor.CallerRunsPolicy()) { |
| | | @Override |
| | | protected void afterExecute(Runnable r, Throwable t) { |
| | | super.afterExecute(r, t); |
| | | Threads.printException(r, t); |
| | | } |
| | | }; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config; |
| | | |
| | | import jakarta.validation.Validator; |
| | | import org.hibernate.validator.HibernateValidator; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.MessageSource; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; |
| | | |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * æ ¡éªæ¡æ¶é
置类 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | public class ValidatorConfig { |
| | | |
| | | /** |
| | | * é
ç½®æ ¡éªæ¡æ¶ å¿«éè¿åæ¨¡å¼ |
| | | */ |
| | | @Bean |
| | | public Validator validator(MessageSource messageSource) { |
| | | LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); |
| | | // å½é
å |
| | | factoryBean.setValidationMessageSource(messageSource); |
| | | // è®¾ç½®ä½¿ç¨ HibernateValidator æ ¡éªå¨ |
| | | factoryBean.setProviderClass(HibernateValidator.class); |
| | | Properties properties = new Properties(); |
| | | // 设置 å¿«éå¼å¸¸è¿å |
| | | properties.setProperty("hibernate.validator.fail_fast", "true"); |
| | | factoryBean.setValidationProperties(properties); |
| | | // å è½½é
ç½® |
| | | factoryBean.afterPropertiesSet(); |
| | | return factoryBean.getValidator(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * çº¿ç¨æ± é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "thread-pool") |
| | | public class ThreadPoolProperties { |
| | | |
| | | /** |
| | | * æ¯å¦å¼å¯çº¿ç¨æ± |
| | | */ |
| | | private boolean enabled; |
| | | |
| | | /** |
| | | * éåæå¤§é¿åº¦ |
| | | */ |
| | | private int queueCapacity; |
| | | |
| | | /** |
| | | * çº¿ç¨æ± ç»´æ¤çº¿ç¨æå
许çç©ºé²æ¶é´ |
| | | */ |
| | | private int keepAliveSeconds; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * ç¼åçkey 常é |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface CacheConstants { |
| | | |
| | | /** |
| | | * å¨çº¿ç¨æ· redis key |
| | | */ |
| | | String ONLINE_TOKEN_KEY = "online_tokens:"; |
| | | |
| | | /** |
| | | * åæ°ç®¡ç cache key |
| | | */ |
| | | String SYS_CONFIG_KEY = "sys_config:"; |
| | | |
| | | /** |
| | | * åå
¸ç®¡ç cache key |
| | | */ |
| | | String SYS_DICT_KEY = "sys_dict:"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * ç¼åç»å称常é |
| | | * <p> |
| | | * key æ ¼å¼ä¸º cacheNames#ttl#maxIdleTime#maxSize |
| | | * <p> |
| | | * ttl è¿ææ¶é´ å¦æè®¾ç½®ä¸º0åä¸è¿æ é»è®¤ä¸º0 |
| | | * maxIdleTime æå¤§ç©ºé²æ¶é´ æ ¹æ®LRUç®æ³æ¸
çç©ºé²æ°æ® å¦æè®¾ç½®ä¸º0å䏿£æµ é»è®¤ä¸º0 |
| | | * maxSize ç»æå¤§é¿åº¦ æ ¹æ®LRUç®æ³æ¸
çæº¢åºæ°æ® å¦æè®¾ç½®ä¸º0åæ éé¿ é»è®¤ä¸º0 |
| | | * <p> |
| | | * ä¾å: test#60sãtest#0#60sãtest#0#1m#1000ãtest#1h#0#500 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface CacheNames { |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ¡ä¾ |
| | | */ |
| | | String DEMO_CACHE = "demo:cache#60s#10m#20"; |
| | | |
| | | /** |
| | | * ç³»ç»é
ç½® |
| | | */ |
| | | String SYS_CONFIG = "sys_config"; |
| | | |
| | | /** |
| | | * æ°æ®åå
¸ |
| | | */ |
| | | String SYS_DICT = "sys_dict"; |
| | | |
| | | /** |
| | | * ç§æ· |
| | | */ |
| | | String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; |
| | | |
| | | /** |
| | | * ç¨æ·è´¦æ· |
| | | */ |
| | | String SYS_USER_NAME = "sys_user_name#30d"; |
| | | |
| | | /** |
| | | * é¨é¨ |
| | | */ |
| | | String SYS_DEPT = "sys_dept#30d"; |
| | | |
| | | /** |
| | | * OSSå
容 |
| | | */ |
| | | String SYS_OSS = "sys_oss#30d"; |
| | | |
| | | /** |
| | | * OSSé
ç½® |
| | | */ |
| | | String SYS_OSS_CONFIG = "sys_oss_config"; |
| | | |
| | | /** |
| | | * å¨çº¿ç¨æ· |
| | | */ |
| | | String ONLINE_TOKEN = "online_tokens"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * éç¨å¸¸éä¿¡æ¯ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public interface Constants { |
| | | |
| | | /** |
| | | * UTF-8 å符é |
| | | */ |
| | | String UTF8 = "UTF-8"; |
| | | |
| | | /** |
| | | * GBK å符é |
| | | */ |
| | | String GBK = "GBK"; |
| | | |
| | | /** |
| | | * www主å |
| | | */ |
| | | String WWW = "www."; |
| | | |
| | | /** |
| | | * httpè¯·æ± |
| | | */ |
| | | String HTTP = "http://"; |
| | | |
| | | /** |
| | | * httpsè¯·æ± |
| | | */ |
| | | String HTTPS = "https://"; |
| | | |
| | | /** |
| | | * éç¨æåæ è¯ |
| | | */ |
| | | String SUCCESS = "0"; |
| | | |
| | | /** |
| | | * éç¨å¤±è´¥æ è¯ |
| | | */ |
| | | String FAIL = "1"; |
| | | |
| | | /** |
| | | * ç»å½æå |
| | | */ |
| | | String LOGIN_SUCCESS = "Success"; |
| | | |
| | | /** |
| | | * 注é |
| | | */ |
| | | String LOGOUT = "Logout"; |
| | | |
| | | /** |
| | | * 注å |
| | | */ |
| | | String REGISTER = "Register"; |
| | | |
| | | /** |
| | | * ç»å½å¤±è´¥ |
| | | */ |
| | | String LOGIN_FAIL = "Error"; |
| | | |
| | | /** |
| | | * éªè¯ç æææï¼åéï¼ |
| | | */ |
| | | Integer CAPTCHA_EXPIRATION = 2; |
| | | |
| | | /** |
| | | * 令ç |
| | | */ |
| | | String TOKEN = "token"; |
| | | |
| | | /** |
| | | * 顶级é¨é¨id |
| | | */ |
| | | Long TOP_PARENT_ID = 0L; |
| | | |
| | | } |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * å
¨å±çkey常é (ä¸å¡æ å
³çkey) |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface GlobalConstants { |
| | | |
| | | /** |
| | | * å
¨å± redis key (ä¸å¡æ å
³çkey) |
| | | */ |
| | | String GLOBAL_REDIS_KEY = "global:"; |
| | | |
| | | /** |
| | | * ç»å½ç¨æ· redis key |
| | | */ |
| | | String LOGIN_TOKEN_KEY = GLOBAL_REDIS_KEY + "Authorization:login:token:"; |
| | | |
| | | /** |
| | | * éªè¯ç redis key |
| | | */ |
| | | String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; |
| | | |
| | | /** |
| | | * é²éæäº¤ redis key |
| | | */ |
| | | String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; |
| | | |
| | | /** |
| | | * éæµ redis key |
| | | */ |
| | | String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; |
| | | |
| | | /** |
| | | * ç»å½è´¦æ·å¯ç éè¯¯æ¬¡æ° redis key |
| | | */ |
| | | String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:"; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * è¿åç¶æç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface HttpStatus { |
| | | /** |
| | | * æä½æå |
| | | */ |
| | | int SUCCESS = 200; |
| | | |
| | | /** |
| | | * 对象å建æå |
| | | */ |
| | | int CREATED = 201; |
| | | |
| | | /** |
| | | * 请æ±å·²ç»è¢«æ¥å |
| | | */ |
| | | int ACCEPTED = 202; |
| | | |
| | | /** |
| | | * æä½å·²ç»æ§è¡æåï¼ä½æ¯æ²¡æè¿åæ°æ® |
| | | */ |
| | | int NO_CONTENT = 204; |
| | | |
| | | /** |
| | | * èµæºå·²è¢«ç§»é¤ |
| | | */ |
| | | int MOVED_PERM = 301; |
| | | |
| | | /** |
| | | * éå®å |
| | | */ |
| | | int SEE_OTHER = 303; |
| | | |
| | | /** |
| | | * èµæºæ²¡æè¢«ä¿®æ¹ |
| | | */ |
| | | int NOT_MODIFIED = 304; |
| | | |
| | | /** |
| | | * åæ°å表é误ï¼ç¼ºå°ï¼æ ¼å¼ä¸å¹é
ï¼ |
| | | */ |
| | | int BAD_REQUEST = 400; |
| | | |
| | | /** |
| | | * æªææ |
| | | */ |
| | | int UNAUTHORIZED = 401; |
| | | |
| | | /** |
| | | * 访é®åéï¼ææè¿æ |
| | | */ |
| | | int FORBIDDEN = 403; |
| | | |
| | | /** |
| | | * èµæºï¼æå¡æªæ¾å° |
| | | */ |
| | | int NOT_FOUND = 404; |
| | | |
| | | /** |
| | | * ä¸å
许çhttpæ¹æ³ |
| | | */ |
| | | int BAD_METHOD = 405; |
| | | |
| | | /** |
| | | * èµæºå²çªï¼æè
èµæºè¢«é |
| | | */ |
| | | int CONFLICT = 409; |
| | | |
| | | /** |
| | | * 䏿¯æçæ°æ®ï¼åªä½ç±»å |
| | | */ |
| | | int UNSUPPORTED_TYPE = 415; |
| | | |
| | | /** |
| | | * ç³»ç»å
é¨é误 |
| | | */ |
| | | int ERROR = 500; |
| | | |
| | | /** |
| | | * æ¥å£æªå®ç° |
| | | */ |
| | | int NOT_IMPLEMENTED = 501; |
| | | |
| | | /** |
| | | * ç³»ç»è¦åæ¶æ¯ |
| | | */ |
| | | int WARN = 601; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * ç§æ·å¸¸éä¿¡æ¯ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface TenantConstants { |
| | | |
| | | /** |
| | | * ç§æ·æ£å¸¸ç¶æ |
| | | */ |
| | | String NORMAL = "0"; |
| | | |
| | | /** |
| | | * ç§æ·å°ç¦ç¶æ |
| | | */ |
| | | String DISABLE = "1"; |
| | | |
| | | /** |
| | | * è¶
级管çåID |
| | | */ |
| | | Long SUPER_ADMIN_ID = 1L; |
| | | |
| | | /** |
| | | * è¶
级管çåè§è² roleKey |
| | | */ |
| | | String SUPER_ADMIN_ROLE_KEY = "superadmin"; |
| | | |
| | | /** |
| | | * ç§æ·ç®¡çåè§è² roleKey |
| | | */ |
| | | String TENANT_ADMIN_ROLE_KEY = "admin"; |
| | | |
| | | /** |
| | | * ç§æ·ç®¡çåè§è²åç§° |
| | | */ |
| | | String TENANT_ADMIN_ROLE_NAME = "管çå"; |
| | | |
| | | /** |
| | | * é»è®¤ç§æ·ID |
| | | */ |
| | | String DEFAULT_TENANT_ID = "000000"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.constant; |
| | | |
| | | /** |
| | | * ç¨æ·å¸¸éä¿¡æ¯ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public interface UserConstants { |
| | | |
| | | /** |
| | | * å¹³å°å
ç³»ç»ç¨æ·çå¯ä¸æ å¿ |
| | | */ |
| | | String SYS_USER = "SYS_USER"; |
| | | |
| | | /** |
| | | * æ£å¸¸ç¶æ |
| | | */ |
| | | String NORMAL = "0"; |
| | | |
| | | /** |
| | | * å¼å¸¸ç¶æ |
| | | */ |
| | | String EXCEPTION = "1"; |
| | | |
| | | /** |
| | | * ç¨æ·æ£å¸¸ç¶æ |
| | | */ |
| | | String USER_NORMAL = "0"; |
| | | |
| | | /** |
| | | * ç¨æ·å°ç¦ç¶æ |
| | | */ |
| | | String USER_DISABLE = "1"; |
| | | |
| | | /** |
| | | * è§è²æ£å¸¸ç¶æ |
| | | */ |
| | | String ROLE_NORMAL = "0"; |
| | | |
| | | /** |
| | | * è§è²å°ç¦ç¶æ |
| | | */ |
| | | String ROLE_DISABLE = "1"; |
| | | |
| | | /** |
| | | * é¨é¨æ£å¸¸ç¶æ |
| | | */ |
| | | String DEPT_NORMAL = "0"; |
| | | |
| | | /** |
| | | * é¨é¨åç¨ç¶æ |
| | | */ |
| | | String DEPT_DISABLE = "1"; |
| | | |
| | | /** |
| | | * åå
¸æ£å¸¸ç¶æ |
| | | */ |
| | | String DICT_NORMAL = "0"; |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºç³»ç»é»è®¤ï¼æ¯ï¼ |
| | | */ |
| | | String YES = "Y"; |
| | | |
| | | /** |
| | | * æ¯å¦èåå¤é¾ï¼æ¯ï¼ |
| | | */ |
| | | String YES_FRAME = "0"; |
| | | |
| | | /** |
| | | * æ¯å¦èåå¤é¾ï¼å¦ï¼ |
| | | */ |
| | | String NO_FRAME = "1"; |
| | | |
| | | /** |
| | | * èåæ£å¸¸ç¶æ |
| | | */ |
| | | String MENU_NORMAL = "0"; |
| | | |
| | | /** |
| | | * èååç¨ç¶æ |
| | | */ |
| | | String MENU_DISABLE = "1"; |
| | | |
| | | /** |
| | | * èåç±»åï¼ç®å½ï¼ |
| | | */ |
| | | String TYPE_DIR = "M"; |
| | | |
| | | /** |
| | | * èåç±»åï¼èåï¼ |
| | | */ |
| | | String TYPE_MENU = "C"; |
| | | |
| | | /** |
| | | * èåç±»åï¼æé®ï¼ |
| | | */ |
| | | String TYPE_BUTTON = "F"; |
| | | |
| | | /** |
| | | * Layoutç»ä»¶æ è¯ |
| | | */ |
| | | String LAYOUT = "Layout"; |
| | | |
| | | /** |
| | | * ParentViewç»ä»¶æ è¯ |
| | | */ |
| | | String PARENT_VIEW = "ParentView"; |
| | | |
| | | /** |
| | | * InnerLinkç»ä»¶æ è¯ |
| | | */ |
| | | String INNER_LINK = "InnerLink"; |
| | | |
| | | /** |
| | | * ç¨æ·åé¿åº¦éå¶ |
| | | */ |
| | | int USERNAME_MIN_LENGTH = 2; |
| | | int USERNAME_MAX_LENGTH = 20; |
| | | |
| | | /** |
| | | * å¯ç é¿åº¦éå¶ |
| | | */ |
| | | int PASSWORD_MIN_LENGTH = 5; |
| | | int PASSWORD_MAX_LENGTH = 20; |
| | | |
| | | /** |
| | | * è¶
级管çåID |
| | | */ |
| | | Long SUPER_ADMIN_ID = 1L; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain; |
| | | |
| | | import org.dromara.common.core.constant.HttpStatus; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * ååºä¿¡æ¯ä¸»ä½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class R<T> implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * æå |
| | | */ |
| | | public static final int SUCCESS = 200; |
| | | |
| | | /** |
| | | * 失败 |
| | | */ |
| | | public static final int FAIL = 500; |
| | | |
| | | private int code; |
| | | |
| | | private String msg; |
| | | |
| | | private T data; |
| | | |
| | | public static <T> R<T> ok() { |
| | | return restResult(null, SUCCESS, "æä½æå"); |
| | | } |
| | | |
| | | public static <T> R<T> ok(T data) { |
| | | return restResult(data, SUCCESS, "æä½æå"); |
| | | } |
| | | |
| | | public static <T> R<T> ok(String msg) { |
| | | return restResult(null, SUCCESS, msg); |
| | | } |
| | | |
| | | public static <T> R<T> ok(String msg, T data) { |
| | | return restResult(data, SUCCESS, msg); |
| | | } |
| | | |
| | | public static <T> R<T> fail() { |
| | | return restResult(null, FAIL, "æä½å¤±è´¥"); |
| | | } |
| | | |
| | | public static <T> R<T> fail(String msg) { |
| | | return restResult(null, FAIL, msg); |
| | | } |
| | | |
| | | public static <T> R<T> fail(T data) { |
| | | return restResult(data, FAIL, "æä½å¤±è´¥"); |
| | | } |
| | | |
| | | public static <T> R<T> fail(String msg, T data) { |
| | | return restResult(data, FAIL, msg); |
| | | } |
| | | |
| | | public static <T> R<T> fail(int code, String msg) { |
| | | return restResult(null, code, msg); |
| | | } |
| | | |
| | | /** |
| | | * è¿åè¦åæ¶æ¯ |
| | | * |
| | | * @param msg è¿åå
容 |
| | | * @return è¦åæ¶æ¯ |
| | | */ |
| | | public static <T> R<T> warn(String msg) { |
| | | return restResult(null, HttpStatus.WARN, msg); |
| | | } |
| | | |
| | | /** |
| | | * è¿åè¦åæ¶æ¯ |
| | | * |
| | | * @param msg è¿åå
容 |
| | | * @param data æ°æ®å¯¹è±¡ |
| | | * @return è¦åæ¶æ¯ |
| | | */ |
| | | public static <T> R<T> warn(String msg, T data) { |
| | | return restResult(data, HttpStatus.WARN, msg); |
| | | } |
| | | |
| | | private static <T> R<T> restResult(T data, int code, String msg) { |
| | | R<T> r = new R<>(); |
| | | r.setCode(code); |
| | | r.setData(data); |
| | | r.setMsg(msg); |
| | | return r; |
| | | } |
| | | |
| | | public static <T> Boolean isError(R<T> ret) { |
| | | return !isSuccess(ret); |
| | | } |
| | | |
| | | public static <T> Boolean isSuccess(R<T> ret) { |
| | | return R.SUCCESS == ret.getCode(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.dto; |
| | | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * è§è² |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class RoleDTO implements Serializable { |
| | | |
| | | /** |
| | | * è§è²ID |
| | | */ |
| | | private Long roleId; |
| | | |
| | | /** |
| | | * è§è²åç§° |
| | | */ |
| | | private String roleName; |
| | | |
| | | /** |
| | | * è§è²æé |
| | | */ |
| | | private String roleKey; |
| | | |
| | | /** |
| | | * æ°æ®èå´ï¼1ï¼æææ°æ®æéï¼2ï¼èªå®ä¹æ°æ®æéï¼3ï¼æ¬é¨é¨æ°æ®æéï¼4ï¼æ¬é¨é¨å以䏿°æ®æéï¼5ï¼ä»
æ¬äººæ°æ®æéï¼ |
| | | */ |
| | | private String dataScope; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.dto; |
| | | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * å½åå¨çº¿ä¼è¯ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class UserOnlineDTO implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ä¼è¯ç¼å· |
| | | */ |
| | | private String tokenId; |
| | | |
| | | /** |
| | | * é¨é¨åç§° |
| | | */ |
| | | private String deptName; |
| | | |
| | | /** |
| | | * ç¨æ·åç§° |
| | | */ |
| | | private String userName; |
| | | |
| | | /** |
| | | * ç»å½IPå°å |
| | | */ |
| | | private String ipaddr; |
| | | |
| | | /** |
| | | * ç»å½å°å |
| | | */ |
| | | private String loginLocation; |
| | | |
| | | /** |
| | | * æµè§å¨ç±»å |
| | | */ |
| | | private String browser; |
| | | |
| | | /** |
| | | * æä½ç³»ç» |
| | | */ |
| | | private String os; |
| | | |
| | | /** |
| | | * ç»å½æ¶é´ |
| | | */ |
| | | private Long loginTime; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import jakarta.validation.constraints.Email; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * çä¿¡ç»å½å¯¹è±¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class EmailLoginBody { |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | @NotBlank(message = "{tenant.number.not.blank}") |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * é®ç®± |
| | | */ |
| | | @NotBlank(message = "{user.email.not.blank}") |
| | | @Email(message = "{user.email.not.valid}") |
| | | private String email; |
| | | |
| | | /** |
| | | * é®ç®±code |
| | | */ |
| | | @NotBlank(message = "{email.code.not.blank}") |
| | | private String emailCode; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import org.dromara.common.core.constant.UserConstants; |
| | | import lombok.Data; |
| | | import org.hibernate.validator.constraints.Length; |
| | | |
| | | import jakarta.validation.constraints.NotBlank; |
| | | |
| | | /** |
| | | * ç¨æ·ç»å½å¯¹è±¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class LoginBody { |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | @NotBlank(message = "{tenant.number.not.blank}") |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * ç¨æ·å |
| | | */ |
| | | @NotBlank(message = "{user.username.not.blank}") |
| | | @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") |
| | | private String username; |
| | | |
| | | /** |
| | | * ç¨æ·å¯ç |
| | | */ |
| | | @NotBlank(message = "{user.password.not.blank}") |
| | | @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") |
| | | private String password; |
| | | |
| | | /** |
| | | * éªè¯ç |
| | | */ |
| | | private String code; |
| | | |
| | | /** |
| | | * å¯ä¸æ è¯ |
| | | */ |
| | | private String uuid; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import org.dromara.common.core.domain.dto.RoleDTO; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * ç»å½ç¨æ·èº«ä»½æé |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class LoginUser implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * ç¨æ·ID |
| | | */ |
| | | private Long userId; |
| | | |
| | | /** |
| | | * é¨é¨ID |
| | | */ |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * é¨é¨å |
| | | */ |
| | | private String deptName; |
| | | |
| | | /** |
| | | * ç¨æ·å¯ä¸æ è¯ |
| | | */ |
| | | private String token; |
| | | |
| | | /** |
| | | * ç¨æ·ç±»å |
| | | */ |
| | | private String userType; |
| | | |
| | | /** |
| | | * ç»å½æ¶é´ |
| | | */ |
| | | private Long loginTime; |
| | | |
| | | /** |
| | | * è¿ææ¶é´ |
| | | */ |
| | | private Long expireTime; |
| | | |
| | | /** |
| | | * ç»å½IPå°å |
| | | */ |
| | | private String ipaddr; |
| | | |
| | | /** |
| | | * ç»å½å°ç¹ |
| | | */ |
| | | private String loginLocation; |
| | | |
| | | /** |
| | | * æµè§å¨ç±»å |
| | | */ |
| | | private String browser; |
| | | |
| | | /** |
| | | * æä½ç³»ç» |
| | | */ |
| | | private String os; |
| | | |
| | | /** |
| | | * èåæé |
| | | */ |
| | | private Set<String> menuPermission; |
| | | |
| | | /** |
| | | * è§è²æé |
| | | */ |
| | | private Set<String> rolePermission; |
| | | |
| | | /** |
| | | * ç¨æ·å |
| | | */ |
| | | private String username; |
| | | |
| | | /** |
| | | * è§è²å¯¹è±¡ |
| | | */ |
| | | private List<RoleDTO> roles; |
| | | |
| | | /** |
| | | * æ°æ®æé å½åè§è²ID |
| | | */ |
| | | private Long roleId; |
| | | |
| | | /** |
| | | * è·åç»å½id |
| | | */ |
| | | public String getLoginId() { |
| | | if (userType == null) { |
| | | throw new IllegalArgumentException("ç¨æ·ç±»åä¸è½ä¸ºç©º"); |
| | | } |
| | | if (userId == null) { |
| | | throw new IllegalArgumentException("ç¨æ·IDä¸è½ä¸ºç©º"); |
| | | } |
| | | return userType + ":" + userId; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * ç¨æ·æ³¨å对象 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class RegisterBody extends LoginBody { |
| | | |
| | | private String userType; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import jakarta.validation.constraints.NotBlank; |
| | | |
| | | /** |
| | | * çä¿¡ç»å½å¯¹è±¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class SmsLoginBody { |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | @NotBlank(message = "{tenant.number.not.blank}") |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * ææºå· |
| | | */ |
| | | @NotBlank(message = "{user.phonenumber.not.blank}") |
| | | private String phonenumber; |
| | | |
| | | /** |
| | | * çä¿¡code |
| | | */ |
| | | @NotBlank(message = "{sms.code.not.blank}") |
| | | private String smsCode; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.domain.model; |
| | | |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * å°ç¨åºç»å½ç¨æ·èº«ä»½æé |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @NoArgsConstructor |
| | | public class XcxLoginUser extends LoginUser { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * openid |
| | | */ |
| | | private String openid; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * 设å¤ç±»å |
| | | * é对ä¸å¥ ç¨æ·ä½ç³» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum DeviceType { |
| | | |
| | | /** |
| | | * pc端 |
| | | */ |
| | | PC("pc"), |
| | | |
| | | /** |
| | | * app端 |
| | | */ |
| | | APP("app"), |
| | | |
| | | /** |
| | | * å°ç¨åºç«¯ |
| | | */ |
| | | XCX("xcx"); |
| | | |
| | | private final String device; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * ç»å½ç±»å |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum LoginType { |
| | | |
| | | /** |
| | | * å¯ç ç»å½ |
| | | */ |
| | | PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), |
| | | |
| | | /** |
| | | * çä¿¡ç»å½ |
| | | */ |
| | | SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), |
| | | |
| | | /** |
| | | * é®ç®±ç»å½ |
| | | */ |
| | | EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), |
| | | |
| | | /** |
| | | * å°ç¨åºç»å½ |
| | | */ |
| | | XCX("", ""); |
| | | |
| | | /** |
| | | * ç»å½éè¯è¶
åºéå¶æç¤º |
| | | */ |
| | | final String retryLimitExceed; |
| | | |
| | | /** |
| | | * ç»å½éè¯éå¶è®¡æ°æç¤º |
| | | */ |
| | | final String retryLimitCount; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * ç¨æ·ç¶æ |
| | | * |
| | | * @author LionLi |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum TenantStatus { |
| | | /** |
| | | * æ£å¸¸ |
| | | */ |
| | | OK("0", "æ£å¸¸"), |
| | | /** |
| | | * åç¨ |
| | | */ |
| | | DISABLE("1", "åç¨"), |
| | | /** |
| | | * å é¤ |
| | | */ |
| | | DELETED("2", "å é¤"); |
| | | |
| | | private final String code; |
| | | private final String info; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * ç¨æ·ç¶æ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum UserStatus { |
| | | /** |
| | | * æ£å¸¸ |
| | | */ |
| | | OK("0", "æ£å¸¸"), |
| | | /** |
| | | * åç¨ |
| | | */ |
| | | DISABLE("1", "åç¨"), |
| | | /** |
| | | * å é¤ |
| | | */ |
| | | DELETED("2", "å é¤"); |
| | | |
| | | private final String code; |
| | | private final String info; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.enums; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * 设å¤ç±»å |
| | | * é对å¤å¥ ç¨æ·ä½ç³» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum UserType { |
| | | |
| | | /** |
| | | * pc端 |
| | | */ |
| | | SYS_USER("sys_user"), |
| | | |
| | | /** |
| | | * app端 |
| | | */ |
| | | APP_USER("app_user"); |
| | | |
| | | private final String userType; |
| | | |
| | | public static UserType getUserType(String str) { |
| | | for (UserType value : values()) { |
| | | if (StringUtils.contains(str, value.getUserType())) { |
| | | return value; |
| | | } |
| | | } |
| | | throw new RuntimeException("'UserType' not found By " + str); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ¨¡å¼å¼å¸¸ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class DemoModeException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public DemoModeException() { |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * å
¨å±å¼å¸¸ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class GlobalException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * é误æç¤º |
| | | */ |
| | | private String message; |
| | | |
| | | /** |
| | | * é误æç»ï¼å
é¨è°è¯é误 |
| | | */ |
| | | private String detailMessage; |
| | | |
| | | /** |
| | | * 空æé æ¹æ³ï¼é¿å
ååºååé®é¢ |
| | | */ |
| | | public GlobalException() { |
| | | } |
| | | |
| | | public GlobalException(String message) { |
| | | this.message = message; |
| | | } |
| | | |
| | | public String getDetailMessage() { |
| | | return detailMessage; |
| | | } |
| | | |
| | | public GlobalException setDetailMessage(String detailMessage) { |
| | | this.detailMessage = detailMessage; |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public GlobalException setMessage(String message) { |
| | | this.message = message; |
| | | return this; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * ä¸å¡å¼å¸¸ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public final class ServiceException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * é误ç |
| | | */ |
| | | private Integer code; |
| | | |
| | | /** |
| | | * é误æç¤º |
| | | */ |
| | | private String message; |
| | | |
| | | /** |
| | | * é误æç»ï¼å
é¨è°è¯é误 |
| | | */ |
| | | private String detailMessage; |
| | | |
| | | /** |
| | | * 空æé æ¹æ³ï¼é¿å
ååºååé®é¢ |
| | | */ |
| | | public ServiceException() { |
| | | } |
| | | |
| | | public ServiceException(String message) { |
| | | this.message = message; |
| | | } |
| | | |
| | | public ServiceException(String message, Integer code) { |
| | | this.message = message; |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getDetailMessage() { |
| | | return detailMessage; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public ServiceException setMessage(String message) { |
| | | this.message = message; |
| | | return this; |
| | | } |
| | | |
| | | public ServiceException setDetailMessage(String detailMessage) { |
| | | this.detailMessage = detailMessage; |
| | | return this; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * å·¥å
·ç±»å¼å¸¸ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class UtilException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 8247610319171014183L; |
| | | |
| | | public UtilException(Throwable e) { |
| | | super(e.getMessage(), e); |
| | | } |
| | | |
| | | public UtilException(String message) { |
| | | super(message); |
| | | } |
| | | |
| | | public UtilException(String message, Throwable throwable) { |
| | | super(message, throwable); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.base; |
| | | |
| | | import org.dromara.common.core.utils.MessageUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * åºç¡å¼å¸¸ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @NoArgsConstructor |
| | | public class BaseException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * æå±æ¨¡å |
| | | */ |
| | | private String module; |
| | | |
| | | /** |
| | | * é误ç |
| | | */ |
| | | private String code; |
| | | |
| | | /** |
| | | * é误ç 对åºçåæ° |
| | | */ |
| | | private Object[] args; |
| | | |
| | | /** |
| | | * éè¯¯æ¶æ¯ |
| | | */ |
| | | private String defaultMessage; |
| | | |
| | | public BaseException(String module, String code, Object[] args, String defaultMessage) { |
| | | this.module = module; |
| | | this.code = code; |
| | | this.args = args; |
| | | this.defaultMessage = defaultMessage; |
| | | } |
| | | |
| | | public BaseException(String module, String code, Object[] args) { |
| | | this(module, code, args, null); |
| | | } |
| | | |
| | | public BaseException(String module, String defaultMessage) { |
| | | this(module, null, null, defaultMessage); |
| | | } |
| | | |
| | | public BaseException(String code, Object[] args) { |
| | | this(null, code, args, null); |
| | | } |
| | | |
| | | public BaseException(String defaultMessage) { |
| | | this(null, null, null, defaultMessage); |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | String message = null; |
| | | if (!StringUtils.isEmpty(code)) { |
| | | message = MessageUtils.message(code, args); |
| | | } |
| | | if (message == null) { |
| | | message = defaultMessage; |
| | | } |
| | | return message; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.file; |
| | | |
| | | import org.dromara.common.core.exception.base.BaseException; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æä»¶ä¿¡æ¯å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class FileException extends BaseException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public FileException(String code, Object[] args) { |
| | | super("file", code, args, null); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.file; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æä»¶åç§°è¶
é¿éå¶å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class FileNameLengthLimitExceededException extends FileException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public FileNameLengthLimitExceededException(int defaultFileNameLength) { |
| | | super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.file; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æä»¶å大å°éå¶å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class FileSizeLimitExceededException extends FileException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public FileSizeLimitExceededException(long defaultMaxSize) { |
| | | super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.user; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * éªè¯ç é误å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class CaptchaException extends UserException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public CaptchaException() { |
| | | super("user.jcaptcha.error"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.user; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * éªè¯ç 失æå¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class CaptchaExpireException extends UserException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public CaptchaExpireException() { |
| | | super("user.jcaptcha.expire"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.user; |
| | | |
| | | import org.dromara.common.core.exception.base.BaseException; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * ç¨æ·ä¿¡æ¯å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class UserException extends BaseException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public UserException(String code, Object... args) { |
| | | super("user", code, args, null); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.user; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * ç¨æ·å¯ç 䏿£ç¡®æä¸ç¬¦åè§èå¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class UserPasswordNotMatchException extends UserException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public UserPasswordNotMatchException() { |
| | | super("user.password.not.match"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.exception.user; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * ç¨æ·é误æå¤§æ¬¡æ°å¼å¸¸ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class UserPasswordRetryLimitExceedException extends UserException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) { |
| | | super("user.password.retry.limit.exceed", retryLimitCount, lockTime); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.manager; |
| | | |
| | | import org.dromara.common.core.utils.Threads; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import jakarta.annotation.PreDestroy; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | |
| | | /** |
| | | * ç¡®ä¿åºç¨éåºæ¶è½å
³éåå°çº¿ç¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class ShutdownManager { |
| | | |
| | | @Autowired |
| | | @Qualifier("scheduledExecutorService") |
| | | private ScheduledExecutorService scheduledExecutorService; |
| | | |
| | | @PreDestroy |
| | | public void destroy() { |
| | | shutdownAsyncManager(); |
| | | } |
| | | |
| | | /** |
| | | * 忢弿¥æ§è¡ä»»å¡ |
| | | */ |
| | | private void shutdownAsyncManager() { |
| | | try { |
| | | log.info("====å
³éåå°ä»»å¡ä»»å¡çº¿ç¨æ± ===="); |
| | | Threads.shutdownAndAwaitTermination(scheduledExecutorService); |
| | | } catch (Exception e) { |
| | | log.error(e.getMessage(), e); |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.service; |
| | | |
| | | /** |
| | | * éç¨ åæ°é
ç½®æå¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface ConfigService { |
| | | |
| | | /** |
| | | * æ ¹æ®åæ° key è·ååæ°å¼ |
| | | * |
| | | * @param configKey åæ° key |
| | | * @return åæ°å¼ |
| | | */ |
| | | String getConfigValue(String configKey); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.service; |
| | | |
| | | /** |
| | | * éç¨ é¨é¨æå¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface DeptService { |
| | | |
| | | /** |
| | | * éè¿é¨é¨IDæ¥è¯¢é¨é¨åç§° |
| | | * |
| | | * @param deptIds é¨é¨ID串éå·åé |
| | | * @return é¨é¨å称串éå·åé |
| | | */ |
| | | String selectDeptNameByIds(String deptIds); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.service; |
| | | |
| | | /** |
| | | * éç¨ åå
¸æå¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface DictService { |
| | | |
| | | /** |
| | | * åé符 |
| | | */ |
| | | String SEPARATOR = ","; |
| | | |
| | | /** |
| | | * æ ¹æ®åå
¸ç±»åååå
¸å¼è·ååå
¸æ ç¾ |
| | | * |
| | | * @param dictType åå
¸ç±»å |
| | | * @param dictValue åå
¸å¼ |
| | | * @return åå
¸æ ç¾ |
| | | */ |
| | | default String getDictLabel(String dictType, String dictValue) { |
| | | return getDictLabel(dictType, dictValue, SEPARATOR); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®åå
¸ç±»åååå
¸æ ç¾è·ååå
¸å¼ |
| | | * |
| | | * @param dictType åå
¸ç±»å |
| | | * @param dictLabel åå
¸æ ç¾ |
| | | * @return åå
¸å¼ |
| | | */ |
| | | default String getDictValue(String dictType, String dictLabel) { |
| | | return getDictValue(dictType, dictLabel, SEPARATOR); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®åå
¸ç±»åååå
¸å¼è·ååå
¸æ ç¾ |
| | | * |
| | | * @param dictType åå
¸ç±»å |
| | | * @param dictValue åå
¸å¼ |
| | | * @param separator åé符 |
| | | * @return åå
¸æ ç¾ |
| | | */ |
| | | String getDictLabel(String dictType, String dictValue, String separator); |
| | | |
| | | /** |
| | | * æ ¹æ®åå
¸ç±»åååå
¸æ ç¾è·ååå
¸å¼ |
| | | * |
| | | * @param dictType åå
¸ç±»å |
| | | * @param dictLabel åå
¸æ ç¾ |
| | | * @param separator åé符 |
| | | * @return åå
¸å¼ |
| | | */ |
| | | String getDictValue(String dictType, String dictLabel, String separator); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.service; |
| | | |
| | | /** |
| | | * éç¨ OSSæå¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface OssService { |
| | | |
| | | /** |
| | | * éè¿ossIdæ¥è¯¢å¯¹åºçurl |
| | | * |
| | | * @param ossIds ossId串éå·åé |
| | | * @return url串éå·åé |
| | | */ |
| | | String selectUrlByIds(String ossIds); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.service; |
| | | |
| | | /** |
| | | * éç¨ ç¨æ·æå¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface UserService { |
| | | |
| | | /** |
| | | * éè¿ç¨æ·IDæ¥è¯¢ç¨æ·è´¦æ· |
| | | * |
| | | * @param userId ç¨æ·ID |
| | | * @return ç¨æ·è´¦æ· |
| | | */ |
| | | String selectUserNameById(Long userId); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.apache.commons.lang3.time.DateFormatUtils; |
| | | |
| | | import java.lang.management.ManagementFactory; |
| | | import java.text.ParseException; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.ZoneId; |
| | | import java.time.ZonedDateTime; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * æ¶é´å·¥å
·ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class DateUtils extends org.apache.commons.lang3.time.DateUtils { |
| | | |
| | | public static final String YYYY = "yyyy"; |
| | | |
| | | public static final String YYYY_MM = "yyyy-MM"; |
| | | |
| | | public static final String YYYY_MM_DD = "yyyy-MM-dd"; |
| | | |
| | | public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; |
| | | |
| | | public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; |
| | | |
| | | private static final String[] PARSE_PATTERNS = { |
| | | "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", |
| | | "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", |
| | | "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; |
| | | |
| | | /** |
| | | * è·åå½åDate忥æ |
| | | * |
| | | * @return Date() å½åæ¥æ |
| | | */ |
| | | public static Date getNowDate() { |
| | | return new Date(); |
| | | } |
| | | |
| | | /** |
| | | * è·åå½åæ¥æ, é»è®¤æ ¼å¼ä¸ºyyyy-MM-dd |
| | | * |
| | | * @return String |
| | | */ |
| | | public static String getDate() { |
| | | return dateTimeNow(YYYY_MM_DD); |
| | | } |
| | | |
| | | public static String getTime() { |
| | | return dateTimeNow(YYYY_MM_DD_HH_MM_SS); |
| | | } |
| | | |
| | | public static String dateTimeNow() { |
| | | return dateTimeNow(YYYYMMDDHHMMSS); |
| | | } |
| | | |
| | | public static String dateTimeNow(final String format) { |
| | | return parseDateToStr(format, new Date()); |
| | | } |
| | | |
| | | public static String dateTime(final Date date) { |
| | | return parseDateToStr(YYYY_MM_DD, date); |
| | | } |
| | | |
| | | public static String parseDateToStr(final String format, final Date date) { |
| | | return new SimpleDateFormat(format).format(date); |
| | | } |
| | | |
| | | public static Date dateTime(final String format, final String ts) { |
| | | try { |
| | | return new SimpleDateFormat(format).parse(ts); |
| | | } catch (ParseException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¥æè·¯å¾ å³å¹´/æ/æ¥ å¦2018/08/08 |
| | | */ |
| | | public static String datePath() { |
| | | Date now = new Date(); |
| | | return DateFormatUtils.format(now, "yyyy/MM/dd"); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æè·¯å¾ å³å¹´/æ/æ¥ å¦20180808 |
| | | */ |
| | | public static String dateTime() { |
| | | Date now = new Date(); |
| | | return DateFormatUtils.format(now, "yyyyMMdd"); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æåå符串转åä¸ºæ¥æ æ ¼å¼ |
| | | */ |
| | | public static Date parseDate(Object str) { |
| | | if (str == null) { |
| | | return null; |
| | | } |
| | | try { |
| | | return parseDate(str.toString(), PARSE_PATTERNS); |
| | | } catch (ParseException e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·åæå¡å¨å¯å¨æ¶é´ |
| | | */ |
| | | public static Date getServerStartDate() { |
| | | long time = ManagementFactory.getRuntimeMXBean().getStartTime(); |
| | | return new Date(time); |
| | | } |
| | | |
| | | /** |
| | | * 计ç®ç¸å·®å¤©æ° |
| | | */ |
| | | public static int differentDaysByMillisecond(Date date1, Date date2) { |
| | | return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); |
| | | } |
| | | |
| | | /** |
| | | * 计ç®ä¸¤ä¸ªæ¶é´å·® |
| | | */ |
| | | public static String getDatePoor(Date endDate, Date nowDate) { |
| | | long nd = 1000 * 24 * 60 * 60; |
| | | long nh = 1000 * 60 * 60; |
| | | long nm = 1000 * 60; |
| | | // long ns = 1000; |
| | | // è·å¾ä¸¤ä¸ªæ¶é´çæ¯«ç§æ¶é´å·®å¼ |
| | | long diff = endDate.getTime() - nowDate.getTime(); |
| | | // 计ç®å·®å¤å°å¤© |
| | | long day = diff / nd; |
| | | // 计ç®å·®å¤å°å°æ¶ |
| | | long hour = diff % nd / nh; |
| | | // 计ç®å·®å¤å°åé |
| | | long min = diff % nd % nh / nm; |
| | | // 计ç®å·®å¤å°ç§//è¾åºç»æ |
| | | // long sec = diff % nd % nh % nm / ns; |
| | | return day + "天" + hour + "å°æ¶" + min + "åé"; |
| | | } |
| | | |
| | | /** |
| | | * å¢å LocalDateTime ==> Date |
| | | */ |
| | | public static Date toDate(LocalDateTime temporalAccessor) { |
| | | ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); |
| | | return Date.from(zdt.toInstant()); |
| | | } |
| | | |
| | | /** |
| | | * å¢å LocalDate ==> Date |
| | | */ |
| | | public static Date toDate(LocalDate temporalAccessor) { |
| | | LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); |
| | | ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); |
| | | return Date.from(zdt.toInstant()); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.map.MapUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import io.github.linpeilie.Converter; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Mapstruct å·¥å
·ç±» |
| | | * <p>åèææ¡£ï¼<a href="https://mapstruct.plus/guide/quick-start">mapstruct-plus</a></p> |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class MapstructUtils { |
| | | |
| | | private final static Converter CONVERTER = SpringUtils.getBean(Converter.class); |
| | | |
| | | /** |
| | | * å° T ç±»å对象ï¼è½¬æ¢ä¸º desc ç±»åç对象并è¿å |
| | | * |
| | | * @param source æ°æ®æ¥æºå®ä½ |
| | | * @param desc æè¿°å¯¹è±¡ 转æ¢åç对象 |
| | | * @return desc |
| | | */ |
| | | public static <T, V> V convert(T source, Class<V> desc) { |
| | | if (ObjectUtil.isNull(source)) { |
| | | return null; |
| | | } |
| | | if (ObjectUtil.isNull(desc)) { |
| | | return null; |
| | | } |
| | | return CONVERTER.convert(source, desc); |
| | | } |
| | | |
| | | /** |
| | | * å° T ç±»åå¯¹è±¡ï¼æç
§é
ç½®çæ å°å段è§åï¼ç» desc ç±»åç对象èµå¼å¹¶è¿å desc 对象 |
| | | * |
| | | * @param source æ°æ®æ¥æºå®ä½ |
| | | * @param desc 转æ¢åç对象 |
| | | * @return desc |
| | | */ |
| | | public static <T, V> V convert(T source, V desc) { |
| | | if (ObjectUtil.isNull(source)) { |
| | | return null; |
| | | } |
| | | if (ObjectUtil.isNull(desc)) { |
| | | return null; |
| | | } |
| | | return CONVERTER.convert(source, desc); |
| | | } |
| | | |
| | | /** |
| | | * å° T ç±»åçéåï¼è½¬æ¢ä¸º desc ç±»åçéåå¹¶è¿å |
| | | * |
| | | * @param sourceList æ°æ®æ¥æºå®ä½å表 |
| | | * @param desc æè¿°å¯¹è±¡ 转æ¢åç对象 |
| | | * @return desc |
| | | */ |
| | | public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) { |
| | | if (ObjectUtil.isNull(sourceList)) { |
| | | return null; |
| | | } |
| | | if (CollUtil.isEmpty(sourceList)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | return CONVERTER.convert(sourceList, desc); |
| | | } |
| | | |
| | | /** |
| | | * å° Map 转æ¢ä¸º beanClass ç±»åçéåå¹¶è¿å |
| | | * |
| | | * @param map æ°æ®æ¥æº |
| | | * @param beanClass beanç±» |
| | | * @return bean对象 |
| | | */ |
| | | public static <T> T convert(Map<String, Object> map, Class<T> beanClass) { |
| | | if (MapUtil.isEmpty(map)) { |
| | | return null; |
| | | } |
| | | if (ObjectUtil.isNull(beanClass)) { |
| | | return null; |
| | | } |
| | | return CONVERTER.convert(map, beanClass); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.springframework.context.MessageSource; |
| | | import org.springframework.context.i18n.LocaleContextHolder; |
| | | |
| | | /** |
| | | * è·åi18nèµæºæä»¶ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class MessageUtils { |
| | | |
| | | private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); |
| | | |
| | | /** |
| | | * æ ¹æ®æ¶æ¯é®ååæ° è·åæ¶æ¯ å§æç»spring messageSource |
| | | * |
| | | * @param code æ¶æ¯é® |
| | | * @param args åæ° |
| | | * @return è·åå½é
åç¿»è¯å¼ |
| | | */ |
| | | public static String message(String code, Object... args) { |
| | | return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.extra.servlet.JakartaServletUtil; |
| | | import cn.hutool.http.HttpStatus; |
| | | import jakarta.servlet.ServletRequest; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.servlet.http.HttpSession; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.web.context.request.RequestAttributes; |
| | | import org.springframework.web.context.request.RequestContextHolder; |
| | | import org.springframework.web.context.request.ServletRequestAttributes; |
| | | |
| | | import java.io.IOException; |
| | | import java.net.URLDecoder; |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 客æ·ç«¯å·¥å
·ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class ServletUtils extends JakartaServletUtil { |
| | | |
| | | /** |
| | | * è·åStringåæ° |
| | | */ |
| | | public static String getParameter(String name) { |
| | | return getRequest().getParameter(name); |
| | | } |
| | | |
| | | /** |
| | | * è·åStringåæ° |
| | | */ |
| | | public static String getParameter(String name, String defaultValue) { |
| | | return Convert.toStr(getRequest().getParameter(name), defaultValue); |
| | | } |
| | | |
| | | /** |
| | | * è·åIntegeråæ° |
| | | */ |
| | | public static Integer getParameterToInt(String name) { |
| | | return Convert.toInt(getRequest().getParameter(name)); |
| | | } |
| | | |
| | | /** |
| | | * è·åIntegeråæ° |
| | | */ |
| | | public static Integer getParameterToInt(String name, Integer defaultValue) { |
| | | return Convert.toInt(getRequest().getParameter(name), defaultValue); |
| | | } |
| | | |
| | | /** |
| | | * è·åBooleanåæ° |
| | | */ |
| | | public static Boolean getParameterToBool(String name) { |
| | | return Convert.toBool(getRequest().getParameter(name)); |
| | | } |
| | | |
| | | /** |
| | | * è·åBooleanåæ° |
| | | */ |
| | | public static Boolean getParameterToBool(String name, Boolean defaultValue) { |
| | | return Convert.toBool(getRequest().getParameter(name), defaultValue); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ææè¯·æ±åæ° |
| | | * |
| | | * @param request 请æ±å¯¹è±¡{@link ServletRequest} |
| | | * @return Map |
| | | */ |
| | | public static Map<String, String[]> getParams(ServletRequest request) { |
| | | final Map<String, String[]> map = request.getParameterMap(); |
| | | return Collections.unmodifiableMap(map); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ææè¯·æ±åæ° |
| | | * |
| | | * @param request 请æ±å¯¹è±¡{@link ServletRequest} |
| | | * @return Map |
| | | */ |
| | | public static Map<String, String> getParamMap(ServletRequest request) { |
| | | Map<String, String> params = new HashMap<>(); |
| | | for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) { |
| | | params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR)); |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | /** |
| | | * è·årequest |
| | | */ |
| | | public static HttpServletRequest getRequest() { |
| | | return getRequestAttributes().getRequest(); |
| | | } |
| | | |
| | | /** |
| | | * è·åresponse |
| | | */ |
| | | public static HttpServletResponse getResponse() { |
| | | return getRequestAttributes().getResponse(); |
| | | } |
| | | |
| | | /** |
| | | * è·åsession |
| | | */ |
| | | public static HttpSession getSession() { |
| | | return getRequest().getSession(); |
| | | } |
| | | |
| | | public static ServletRequestAttributes getRequestAttributes() { |
| | | RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); |
| | | return (ServletRequestAttributes) attributes; |
| | | } |
| | | |
| | | /** |
| | | * å°å符串渲æå°å®¢æ·ç«¯ |
| | | * |
| | | * @param response 渲æå¯¹è±¡ |
| | | * @param string å¾
渲æçå符串 |
| | | */ |
| | | public static void renderString(HttpServletResponse response, String string) { |
| | | try { |
| | | response.setStatus(HttpStatus.HTTP_OK); |
| | | response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
| | | response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); |
| | | response.getWriter().print(string); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦æ¯Ajax弿¥è¯·æ± |
| | | * |
| | | * @param request |
| | | */ |
| | | public static boolean isAjaxRequest(HttpServletRequest request) { |
| | | |
| | | String accept = request.getHeader("accept"); |
| | | if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) { |
| | | return true; |
| | | } |
| | | |
| | | String xRequestedWith = request.getHeader("X-Requested-With"); |
| | | if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { |
| | | return true; |
| | | } |
| | | |
| | | String uri = request.getRequestURI(); |
| | | if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { |
| | | return true; |
| | | } |
| | | |
| | | String ajax = request.getParameter("__ajax"); |
| | | return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); |
| | | } |
| | | |
| | | public static String getClientIP() { |
| | | return getClientIP(getRequest()); |
| | | } |
| | | |
| | | /** |
| | | * å
容ç¼ç |
| | | * |
| | | * @param str å
容 |
| | | * @return ç¼ç åçå
容 |
| | | */ |
| | | public static String urlEncode(String str) { |
| | | return URLEncoder.encode(str, StandardCharsets.UTF_8); |
| | | } |
| | | |
| | | /** |
| | | * å
容解ç |
| | | * |
| | | * @param str å
容 |
| | | * @return è§£ç åçå
容 |
| | | */ |
| | | public static String urlDecode(String str) { |
| | | return URLDecoder.decode(str, StandardCharsets.UTF_8); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.extra.spring.SpringUtil; |
| | | import org.springframework.aop.framework.AopContext; |
| | | import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
| | | import org.springframework.context.ApplicationContext; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * springå·¥å
·ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Component |
| | | public final class SpringUtils extends SpringUtil { |
| | | |
| | | /** |
| | | * 妿BeanFactoryå
å«ä¸ä¸ªä¸æç»åç§°å¹é
çbeanå®ä¹ï¼åè¿åtrue |
| | | */ |
| | | public static boolean containsBean(String name) { |
| | | return getBeanFactory().containsBean(name); |
| | | } |
| | | |
| | | /** |
| | | * 夿以ç»å®ååæ³¨åçbeanå®ä¹æ¯ä¸ä¸ªsingletonè¿æ¯ä¸ä¸ªprototypeã |
| | | * 妿ä¸ç»å®ååç¸åºçbeanå®ä¹æ²¡æè¢«æ¾å°ï¼å°ä¼æåºä¸ä¸ªå¼å¸¸ï¼NoSuchBeanDefinitionExceptionï¼ |
| | | */ |
| | | public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { |
| | | return getBeanFactory().isSingleton(name); |
| | | } |
| | | |
| | | /** |
| | | * @return Class 注å对象çç±»å |
| | | */ |
| | | public static Class<?> getType(String name) throws NoSuchBeanDefinitionException { |
| | | return getBeanFactory().getType(name); |
| | | } |
| | | |
| | | /** |
| | | * 妿ç»å®çbeanååå¨beanå®ä¹ä¸æå«åï¼åè¿åè¿äºå«å |
| | | */ |
| | | public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { |
| | | return getBeanFactory().getAliases(name); |
| | | } |
| | | |
| | | /** |
| | | * è·åaop代ç对象 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> T getAopProxy(T invoker) { |
| | | return (T) AopContext.currentProxy(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * è·åspringä¸ä¸æ |
| | | */ |
| | | public static ApplicationContext context() { |
| | | return getApplicationContext(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.map.MapUtil; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.*; |
| | | import java.util.function.BiFunction; |
| | | import java.util.function.Function; |
| | | import java.util.function.Predicate; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * stream æµå·¥å
·ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class StreamUtils { |
| | | |
| | | /** |
| | | * å°collectionè¿æ»¤ |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param function è¿æ»¤æ¹æ³ |
| | | * @return è¿æ»¤åçlist |
| | | */ |
| | | public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | // æ³¨ææ¤å¤ä¸è¦ä½¿ç¨ .toList() æ°è¯æ³ å 为è¿åçæ¯ä¸å¯åList ä¼å¯¼è´åºååé®é¢ |
| | | return collection.stream().filter(function).collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæ¼æ¥ |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param function æ¼æ¥æ¹æ³ |
| | | * @return æ¼æ¥åçlist |
| | | */ |
| | | public static <E> String join(Collection<E> collection, Function<E, String> function) { |
| | | return join(collection, function, StringUtils.SEPARATOR); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæ¼æ¥ |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param function æ¼æ¥æ¹æ³ |
| | | * @param delimiter æ¼æ¥ç¬¦ |
| | | * @return æ¼æ¥åçlist |
| | | */ |
| | | public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return StringUtils.EMPTY; |
| | | } |
| | | return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæåº |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param comparing æåºæ¹æ³ |
| | | * @return æåºåçlist |
| | | */ |
| | | public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | // æ³¨ææ¤å¤ä¸è¦ä½¿ç¨ .toList() æ°è¯æ³ å 为è¿åçæ¯ä¸å¯åList ä¼å¯¼è´åºååé®é¢ |
| | | return collection.stream().sorted(comparing).collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | | * å°collection转å为类åä¸åçmap<br> |
| | | * <B>{@code Collection<V> ----> Map<K,V>}</B> |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param key Vç±»å转å为Kç±»åçlambdaæ¹æ³ |
| | | * @param <V> collectionä¸çæ³å |
| | | * @param <K> mapä¸çkeyç±»å |
| | | * @return 转ååçmap |
| | | */ |
| | | public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return MapUtil.newHashMap(); |
| | | } |
| | | return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); |
| | | } |
| | | |
| | | /** |
| | | * å°Collection转å为map(valueç±»åä¸collectionçæ³åä¸å)<br> |
| | | * <B>{@code Collection<E> -----> Map<K,V> }</B> |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param key Eç±»å转å为Kç±»åçlambdaæ¹æ³ |
| | | * @param value Eç±»å转å为Vç±»åçlambdaæ¹æ³ |
| | | * @param <E> collectionä¸çæ³å |
| | | * @param <K> mapä¸çkeyç±»å |
| | | * @param <V> mapä¸çvalueç±»å |
| | | * @return 转ååçmap |
| | | */ |
| | | public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return MapUtil.newHashMap(); |
| | | } |
| | | return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l)); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæç
§è§å(æ¯å¦æç¸åçç级id)åç±»æmap<br> |
| | | * <B>{@code Collection<E> -------> Map<K,List<E>> } </B> |
| | | * |
| | | * @param collection éè¦åç±»çéå |
| | | * @param key åç±»çè§å |
| | | * @param <E> collectionä¸çæ³å |
| | | * @param <K> mapä¸çkeyç±»å |
| | | * @return åç±»åçmap |
| | | */ |
| | | public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return MapUtil.newHashMap(); |
| | | } |
| | | return collection |
| | | .stream() |
| | | .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæç
§ä¸¤ä¸ªè§å(æ¯å¦æç¸åç年级id,ç级id)åç±»æåå±map<br> |
| | | * <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B> |
| | | * |
| | | * @param collection éè¦åç±»çéå |
| | | * @param key1 第ä¸ä¸ªåç±»çè§å |
| | | * @param key2 第äºä¸ªåç±»çè§å |
| | | * @param <E> éåå
ç´ ç±»å |
| | | * @param <K> 第ä¸ä¸ªmapä¸çkeyç±»å |
| | | * @param <U> 第äºä¸ªmapä¸çkeyç±»å |
| | | * @return åç±»åçmap |
| | | */ |
| | | public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return MapUtil.newHashMap(); |
| | | } |
| | | return collection |
| | | .stream() |
| | | .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); |
| | | } |
| | | |
| | | /** |
| | | * å°collectionæç
§ä¸¤ä¸ªè§å(æ¯å¦æç¸åç年级id,ç级id)åç±»æåå±map<br> |
| | | * <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B> |
| | | * |
| | | * @param collection éè¦åç±»çéå |
| | | * @param key1 第ä¸ä¸ªåç±»çè§å |
| | | * @param key2 第äºä¸ªåç±»çè§å |
| | | * @param <T> 第ä¸ä¸ªmapä¸çkeyç±»å |
| | | * @param <U> 第äºä¸ªmapä¸çkeyç±»å |
| | | * @param <E> collectionä¸çæ³å |
| | | * @return åç±»åçmap |
| | | */ |
| | | public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) { |
| | | if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { |
| | | return MapUtil.newHashMap(); |
| | | } |
| | | return collection |
| | | .stream() |
| | | .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); |
| | | } |
| | | |
| | | /** |
| | | * å°collection转å为Listéåï¼ä½æ¯ä¸¤è
çæ³åä¸å<br> |
| | | * <B>{@code Collection<E> ------> List<T> } </B> |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param function collectionä¸çæ³å转å为listæ³åçlambdaè¡¨è¾¾å¼ |
| | | * @param <E> collectionä¸çæ³å |
| | | * @param <T> Listä¸çæ³å |
| | | * @return 转ååçlist |
| | | */ |
| | | public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) { |
| | | if (CollUtil.isEmpty(collection)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | return collection |
| | | .stream() |
| | | .map(function) |
| | | .filter(Objects::nonNull) |
| | | // æ³¨ææ¤å¤ä¸è¦ä½¿ç¨ .toList() æ°è¯æ³ å 为è¿åçæ¯ä¸å¯åList ä¼å¯¼è´åºååé®é¢ |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | | * å°collection转å为Setéåï¼ä½æ¯ä¸¤è
çæ³åä¸å<br> |
| | | * <B>{@code Collection<E> ------> Set<T> } </B> |
| | | * |
| | | * @param collection éè¦è½¬åçéå |
| | | * @param function collectionä¸çæ³å转å为setæ³åçlambdaè¡¨è¾¾å¼ |
| | | * @param <E> collectionä¸çæ³å |
| | | * @param <T> Setä¸çæ³å |
| | | * @return 转ååçSet |
| | | */ |
| | | public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) { |
| | | if (CollUtil.isEmpty(collection) || function == null) { |
| | | return CollUtil.newHashSet(); |
| | | } |
| | | return collection |
| | | .stream() |
| | | .map(function) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * å并两个ç¸åkeyç±»åçmap |
| | | * |
| | | * @param map1 第ä¸ä¸ªéè¦åå¹¶ç map |
| | | * @param map2 第äºä¸ªéè¦åå¹¶ç map |
| | | * @param merge åå¹¶çlambdaï¼å°key value1 value2åå¹¶ææç»çç±»å,注ævalueå¯è½ä¸ºç©ºçæ
åµ |
| | | * @param <K> mapä¸çkeyç±»å |
| | | * @param <X> 第ä¸ä¸ª mapçvalueç±»å |
| | | * @param <Y> 第äºä¸ª mapçvalueç±»å |
| | | * @param <V> æç»mapçvalueç±»å |
| | | * @return åå¹¶åçmap |
| | | */ |
| | | public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) { |
| | | if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { |
| | | return MapUtil.newHashMap(); |
| | | } else if (MapUtil.isEmpty(map1)) { |
| | | map1 = MapUtil.newHashMap(); |
| | | } else if (MapUtil.isEmpty(map2)) { |
| | | map2 = MapUtil.newHashMap(); |
| | | } |
| | | Set<K> key = new HashSet<>(); |
| | | key.addAll(map1.keySet()); |
| | | key.addAll(map2.keySet()); |
| | | Map<K, V> map = new HashMap<>(); |
| | | for (K t : key) { |
| | | X x = map1.get(t); |
| | | Y y = map2.get(t); |
| | | V z = merge.apply(x, y); |
| | | if (z != null) { |
| | | map.put(t, z); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.core.lang.Validator; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.springframework.util.AntPathMatcher; |
| | | |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * å符串工å
·ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class StringUtils extends org.apache.commons.lang3.StringUtils { |
| | | |
| | | public static final String SEPARATOR = ","; |
| | | |
| | | /** |
| | | * è·ååæ°ä¸ä¸ºç©ºå¼ |
| | | * |
| | | * @param str defaultValue è¦å¤æçvalue |
| | | * @return value è¿åå¼ |
| | | */ |
| | | public static String blankToDefault(String str, String defaultValue) { |
| | | return StrUtil.blankToDefault(str, defaultValue); |
| | | } |
| | | |
| | | /** |
| | | * * 夿ä¸ä¸ªå符串æ¯å¦ä¸ºç©ºä¸² |
| | | * |
| | | * @param str String |
| | | * @return trueï¼ä¸ºç©º falseï¼é空 |
| | | */ |
| | | public static boolean isEmpty(String str) { |
| | | return StrUtil.isEmpty(str); |
| | | } |
| | | |
| | | /** |
| | | * * 夿ä¸ä¸ªå符串æ¯å¦ä¸ºé空串 |
| | | * |
| | | * @param str String |
| | | * @return trueï¼é空串 falseï¼ç©ºä¸² |
| | | */ |
| | | public static boolean isNotEmpty(String str) { |
| | | return !isEmpty(str); |
| | | } |
| | | |
| | | /** |
| | | * å»ç©ºæ ¼ |
| | | */ |
| | | public static String trim(String str) { |
| | | return StrUtil.trim(str); |
| | | } |
| | | |
| | | /** |
| | | * æªåå符串 |
| | | * |
| | | * @param str å符串 |
| | | * @param start å¼å§ |
| | | * @return ç»æ |
| | | */ |
| | | public static String substring(final String str, int start) { |
| | | return substring(str, start, str.length()); |
| | | } |
| | | |
| | | /** |
| | | * æªåå符串 |
| | | * |
| | | * @param str å符串 |
| | | * @param start å¼å§ |
| | | * @param end ç»æ |
| | | * @return ç»æ |
| | | */ |
| | | public static String substring(final String str, int start, int end) { |
| | | return StrUtil.sub(str, start, end); |
| | | } |
| | | |
| | | /** |
| | | * æ ¼å¼åææ¬, {} 表示å ä½ç¬¦<br> |
| | | * æ¤æ¹æ³åªæ¯ç®åå°å ä½ç¬¦ {} æç
§é¡ºåºæ¿æ¢ä¸ºåæ°<br> |
| | | * 妿æ³è¾åº {} ä½¿ç¨ \\è½¬ä¹ { å³å¯ï¼å¦ææ³è¾åº {} ä¹åç \ 使ç¨å转ä¹ç¬¦ \\\\ å³å¯<br> |
| | | * ä¾ï¼<br> |
| | | * é常使ç¨ï¼format("this is {} for {}", "a", "b") -> this is a for b<br> |
| | | * 转ä¹{}ï¼ format("this is \\{} for {}", "a", "b") -> this is {} for a<br> |
| | | * 转ä¹\ï¼ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> |
| | | * |
| | | * @param template ææ¬æ¨¡æ¿ï¼è¢«æ¿æ¢çé¨åç¨ {} 表示 |
| | | * @param params åæ°å¼ |
| | | * @return æ ¼å¼ååçææ¬ |
| | | */ |
| | | public static String format(String template, Object... params) { |
| | | return StrUtil.format(template, params); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºhttp(s)://å¼å¤´ |
| | | * |
| | | * @param link 龿¥ |
| | | * @return ç»æ |
| | | */ |
| | | public static boolean ishttp(String link) { |
| | | return Validator.isUrl(link); |
| | | } |
| | | |
| | | /** |
| | | * å符串转set |
| | | * |
| | | * @param str å符串 |
| | | * @param sep åé符 |
| | | * @return setéå |
| | | */ |
| | | public static Set<String> str2Set(String str, String sep) { |
| | | return new HashSet<>(str2List(str, sep, true, false)); |
| | | } |
| | | |
| | | /** |
| | | * å符串转list |
| | | * |
| | | * @param str å符串 |
| | | * @param sep åé符 |
| | | * @param filterBlank è¿æ»¤çº¯ç©ºç½ |
| | | * @param trim 廿é¦å°¾ç©ºç½ |
| | | * @return listéå |
| | | */ |
| | | public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) { |
| | | List<String> list = new ArrayList<>(); |
| | | if (isEmpty(str)) { |
| | | return list; |
| | | } |
| | | |
| | | // è¿æ»¤ç©ºç½å符串 |
| | | if (filterBlank && isBlank(str)) { |
| | | return list; |
| | | } |
| | | String[] split = str.split(sep); |
| | | for (String string : split) { |
| | | if (filterBlank && isBlank(string)) { |
| | | continue; |
| | | } |
| | | if (trim) { |
| | | string = trim(string); |
| | | } |
| | | list.add(string); |
| | | } |
| | | |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å
嫿å®å符串å表ä¸çä»»æä¸ä¸ªåç¬¦ä¸²åæ¶ä¸²å¿½ç¥å¤§å°å |
| | | * |
| | | * @param cs æå®å符串 |
| | | * @param searchCharSequences éè¦æ£æ¥çå符串æ°ç» |
| | | * @return æ¯å¦å
å«ä»»æä¸ä¸ªå符串 |
| | | */ |
| | | public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { |
| | | return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); |
| | | } |
| | | |
| | | /** |
| | | * 驼峰转ä¸å线å½å |
| | | */ |
| | | public static String toUnderScoreCase(String str) { |
| | | return StrUtil.toUnderlineCase(str); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦å
å«å符串 |
| | | * |
| | | * @param str éªè¯å符串 |
| | | * @param strs åç¬¦ä¸²ç» |
| | | * @return å
å«è¿åtrue |
| | | */ |
| | | public static boolean inStringIgnoreCase(String str, String... strs) { |
| | | return StrUtil.equalsAnyIgnoreCase(str, strs); |
| | | } |
| | | |
| | | /** |
| | | * å°ä¸åçº¿å¤§åæ¹å¼å½åçå符串转æ¢ä¸ºé©¼å³°å¼ãå¦æè½¬æ¢åçä¸åçº¿å¤§åæ¹å¼å½åçå符串为空ï¼åè¿å空å符串ã ä¾å¦ï¼HELLO_WORLD->HelloWorld |
| | | * |
| | | * @param name 转æ¢åçä¸åçº¿å¤§åæ¹å¼å½åçå符串 |
| | | * @return 转æ¢åç驼峰å¼å½åçå符串 |
| | | */ |
| | | public static String convertToCamelCase(String name) { |
| | | return StrUtil.upperFirst(StrUtil.toCamelCase(name)); |
| | | } |
| | | |
| | | /** |
| | | * 驼峰å¼å½åæ³ ä¾å¦ï¼user_name->userName |
| | | */ |
| | | public static String toCamelCase(String s) { |
| | | return StrUtil.toCamelCase(s); |
| | | } |
| | | |
| | | /** |
| | | * æ¥æ¾æå®å符串æ¯å¦å¹é
æå®å符串å表ä¸çä»»æä¸ä¸ªå符串 |
| | | * |
| | | * @param str æå®å符串 |
| | | * @param strs éè¦æ£æ¥çå符串æ°ç» |
| | | * @return æ¯å¦å¹é
|
| | | */ |
| | | public static boolean matches(String str, List<String> strs) { |
| | | if (isEmpty(str) || CollUtil.isEmpty(strs)) { |
| | | return false; |
| | | } |
| | | for (String pattern : strs) { |
| | | if (isMatch(pattern, str)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 夿urlæ¯å¦ä¸è§åé
ç½®: |
| | | * ? 表示å个å符; |
| | | * * 表示ä¸å±è·¯å¾å
çä»»æå符串ï¼ä¸å¯è·¨å±çº§; |
| | | * ** 表示任æå±è·¯å¾; |
| | | * |
| | | * @param pattern å¹é
è§å |
| | | * @param url éè¦å¹é
çurl |
| | | */ |
| | | public static boolean isMatch(String pattern, String url) { |
| | | AntPathMatcher matcher = new AntPathMatcher(); |
| | | return matcher.match(pattern, url); |
| | | } |
| | | |
| | | /** |
| | | * æ°å左边补é½0ï¼ä½¿ä¹è¾¾å°æå®é¿åº¦ã注æï¼å¦ææ°å转æ¢ä¸ºå符串åï¼é¿åº¦å¤§äºsizeï¼ååªä¿ç æåsize个å符ã |
| | | * |
| | | * @param num æ°å对象 |
| | | * @param size å符串æå®é¿åº¦ |
| | | * @return è¿åæ°åçåç¬¦ä¸²æ ¼å¼ï¼è¯¥å符串为æå®é¿åº¦ã |
| | | */ |
| | | public static String padl(final Number num, final int size) { |
| | | return padl(num.toString(), size, '0'); |
| | | } |
| | | |
| | | /** |
| | | * å符串左补é½ã妿åå§å符串sé¿åº¦å¤§äºsizeï¼ååªä¿çæåsize个å符ã |
| | | * |
| | | * @param s åå§å符串 |
| | | * @param size å符串æå®é¿åº¦ |
| | | * @param c ç¨äºè¡¥é½çå符 |
| | | * @return è¿åæå®é¿åº¦çå符串ï¼ç±ååç¬¦ä¸²å·¦è¡¥é½ææªåå¾å°ã |
| | | */ |
| | | public static String padl(final String s, final int size, final char c) { |
| | | final StringBuilder sb = new StringBuilder(size); |
| | | if (s != null) { |
| | | final int len = s.length(); |
| | | if (s.length() <= size) { |
| | | sb.append(String.valueOf(c).repeat(size - len)); |
| | | sb.append(s); |
| | | } else { |
| | | return s.substring(len - size, len); |
| | | } |
| | | } else { |
| | | sb.append(String.valueOf(c).repeat(Math.max(0, size))); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串(åé符é»è®¤éå·) |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @return åå²åçæ°æ®å表 |
| | | */ |
| | | public static List<String> splitList(String str) { |
| | | return splitTo(str, Convert::toStr); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串 |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符 |
| | | * @return åå²åçæ°æ®å表 |
| | | */ |
| | | public static List<String> splitList(String str, String separator) { |
| | | return splitTo(str, separator, Convert::toStr); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串èªå®ä¹è½¬æ¢(åé符é»è®¤éå·) |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param mapper èªå®ä¹è½¬æ¢ |
| | | * @return åå²åçæ°æ®å表 |
| | | */ |
| | | public static <T> List<T> splitTo(String str, Function<? super Object, T> mapper) { |
| | | return splitTo(str, SEPARATOR, mapper); |
| | | } |
| | | |
| | | /** |
| | | * ååå符串èªå®ä¹è½¬æ¢ |
| | | * |
| | | * @param str 被ååçå符串 |
| | | * @param separator åé符 |
| | | * @param mapper èªå®ä¹è½¬æ¢ |
| | | * @return åå²åçæ°æ®å表 |
| | | */ |
| | | public static <T> List<T> splitTo(String str, String separator, Function<? super Object, T> mapper) { |
| | | if (isBlank(str)) { |
| | | return new ArrayList<>(0); |
| | | } |
| | | return StrUtil.split(str, separator) |
| | | .stream() |
| | | .filter(Objects::nonNull) |
| | | .map(mapper) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.concurrent.*; |
| | | |
| | | /** |
| | | * 线ç¨ç¸å
³å·¥å
·ç±». |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Slf4j |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class Threads { |
| | | |
| | | /** |
| | | * sleepçå¾
,åä½ä¸ºæ¯«ç§ |
| | | */ |
| | | public static void sleep(long milliseconds) { |
| | | try { |
| | | Thread.sleep(milliseconds); |
| | | } catch (InterruptedException e) { |
| | | return; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åæ¢çº¿ç¨æ± |
| | | * å
使ç¨shutdown, åæ¢æ¥æ¶æ°ä»»å¡å¹¶å°è¯å®æææå·²åå¨ä»»å¡. |
| | | * 妿è¶
æ¶, åè°ç¨shutdownNow, åæ¶å¨workQueueä¸Pendingçä»»å¡,并䏿ææé»å¡å½æ°. |
| | | * 妿ä»ç¶è¶
æï¼åå¼·å¶éåº. |
| | | * å¦å¯¹å¨shutdownæ¶çº¿ç¨æ¬èº«è¢«è°ç¨ä¸æåäºå¤ç. |
| | | */ |
| | | public static void shutdownAndAwaitTermination(ExecutorService pool) { |
| | | if (pool != null && !pool.isShutdown()) { |
| | | pool.shutdown(); |
| | | try { |
| | | if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { |
| | | pool.shutdownNow(); |
| | | if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { |
| | | log.info("Pool did not terminate"); |
| | | } |
| | | } |
| | | } catch (InterruptedException ie) { |
| | | pool.shutdownNow(); |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æå°çº¿ç¨å¼å¸¸ä¿¡æ¯ |
| | | */ |
| | | public static void printException(Runnable r, Throwable t) { |
| | | if (t == null && r instanceof Future<?>) { |
| | | try { |
| | | Future<?> future = (Future<?>) r; |
| | | if (future.isDone()) { |
| | | future.get(); |
| | | } |
| | | } catch (CancellationException ce) { |
| | | t = ce; |
| | | } catch (ExecutionException ee) { |
| | | t = ee.getCause(); |
| | | } catch (InterruptedException ie) { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | if (t != null) { |
| | | log.error(t.getMessage(), t); |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.lang.tree.Tree; |
| | | import cn.hutool.core.lang.tree.TreeNodeConfig; |
| | | import cn.hutool.core.lang.tree.TreeUtil; |
| | | import cn.hutool.core.lang.tree.parser.NodeParser; |
| | | import org.dromara.common.core.utils.reflect.ReflectUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ©å± hutool TreeUtil å°è£
ç³»ç»æ æå»º |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class TreeBuildUtils extends TreeUtil { |
| | | |
| | | /** |
| | | * æ ¹æ®å端å®å¶å·®å¼ååæ®µ |
| | | */ |
| | | public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); |
| | | |
| | | public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return null; |
| | | } |
| | | K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); |
| | | return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils; |
| | | |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import jakarta.validation.ConstraintViolation; |
| | | import jakarta.validation.ConstraintViolationException; |
| | | import jakarta.validation.Validator; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * Validator æ ¡éªæ¡æ¶å·¥å
· |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class ValidatorUtils { |
| | | |
| | | private static final Validator VALID = SpringUtils.getBean(Validator.class); |
| | | |
| | | public static <T> void validate(T object, Class<?>... groups) { |
| | | Set<ConstraintViolation<T>> validate = VALID.validate(object, groups); |
| | | if (!validate.isEmpty()) { |
| | | throw new ConstraintViolationException("åæ°æ ¡éªå¼å¸¸", validate); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.file; |
| | | |
| | | import cn.hutool.core.io.FileUtil; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | |
| | | /** |
| | | * æä»¶å¤çå·¥å
·ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class FileUtils extends FileUtil { |
| | | |
| | | /** |
| | | * ä¸è½½æä»¶åéæ°ç¼ç |
| | | * |
| | | * @param response ååºå¯¹è±¡ |
| | | * @param realFileName ç宿件å |
| | | */ |
| | | public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) { |
| | | String percentEncodedFileName = percentEncode(realFileName); |
| | | String contentDispositionValue = "attachment; filename=%s;filename*=utf-8''%s".formatted(percentEncodedFileName, percentEncodedFileName); |
| | | response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); |
| | | response.setHeader("Content-disposition", contentDispositionValue); |
| | | response.setHeader("download-filename", percentEncodedFileName); |
| | | } |
| | | |
| | | /** |
| | | * ç¾åå·ç¼ç å·¥å
·æ¹æ³ |
| | | * |
| | | * @param s éè¦ç¾åå·ç¼ç çå符串 |
| | | * @return ç¾åå·ç¼ç åçå符串 |
| | | */ |
| | | public static String percentEncode(String s) { |
| | | String encode = URLEncoder.encode(s, StandardCharsets.UTF_8); |
| | | return encode.replaceAll("\\+", "%20"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.file; |
| | | |
| | | /** |
| | | * åªä½ç±»åå·¥å
·ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class MimeTypeUtils { |
| | | public static final String IMAGE_PNG = "image/png"; |
| | | |
| | | public static final String IMAGE_JPG = "image/jpg"; |
| | | |
| | | public static final String IMAGE_JPEG = "image/jpeg"; |
| | | |
| | | public static final String IMAGE_BMP = "image/bmp"; |
| | | |
| | | public static final String IMAGE_GIF = "image/gif"; |
| | | |
| | | public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; |
| | | |
| | | public static final String[] FLASH_EXTENSION = {"swf", "flv"}; |
| | | |
| | | public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", |
| | | "asf", "rm", "rmvb"}; |
| | | |
| | | public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; |
| | | |
| | | public static final String[] DEFAULT_ALLOWED_EXTENSION = { |
| | | // å¾ç |
| | | "bmp", "gif", "jpg", "jpeg", "png", |
| | | // word excel powerpoint |
| | | "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", |
| | | // å缩æä»¶ |
| | | "rar", "zip", "gz", "bz2", |
| | | // è§é¢æ ¼å¼ |
| | | "mp4", "avi", "rmvb", |
| | | // pdf |
| | | "pdf"}; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.ip; |
| | | |
| | | import cn.hutool.core.net.NetUtil; |
| | | import cn.hutool.http.HtmlUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | /** |
| | | * è·åå°åç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class AddressUtils { |
| | | |
| | | // æªç¥å°å |
| | | public static final String UNKNOWN = "XX XX"; |
| | | |
| | | public static String getRealAddressByIP(String ip) { |
| | | if (StringUtils.isBlank(ip)) { |
| | | return UNKNOWN; |
| | | } |
| | | // å
ç½ä¸æ¥è¯¢ |
| | | ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); |
| | | if (NetUtil.isInnerIP(ip)) { |
| | | return "å
ç½IP"; |
| | | } |
| | | return RegionUtils.getCityInfo(ip); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.ip; |
| | | |
| | | import cn.hutool.core.io.FileUtil; |
| | | import cn.hutool.core.io.resource.ClassPathResource; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.file.FileUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.lionsoul.ip2region.xdb.Searcher; |
| | | |
| | | import java.io.File; |
| | | |
| | | /** |
| | | * æ ¹æ®ipå°åå®ä½å·¥å
·ç±»ï¼ç¦»çº¿æ¹å¼ |
| | | * åèå°åï¼<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">éæ ip2region å®ç°ç¦»çº¿IPå°åå®ä½åº</a> |
| | | * |
| | | * @author lishuyan |
| | | */ |
| | | @Slf4j |
| | | public class RegionUtils { |
| | | |
| | | private static final Searcher SEARCHER; |
| | | |
| | | static { |
| | | String fileName = "/ip2region.xdb"; |
| | | File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName); |
| | | if (!FileUtils.exist(existFile)) { |
| | | ClassPathResource fileStream = new ClassPathResource(fileName); |
| | | if (ObjectUtil.isEmpty(fileStream.getStream())) { |
| | | throw new ServiceException("RegionUtilsåå§å失败ï¼åå ï¼IPå°ååºæ°æ®ä¸åå¨ï¼"); |
| | | } |
| | | FileUtils.writeFromStream(fileStream.getStream(), existFile); |
| | | } |
| | | |
| | | String dbPath = existFile.getPath(); |
| | | |
| | | // 1ãä» dbPath å è½½æ´ä¸ª xdb å°å
åã |
| | | byte[] cBuff; |
| | | try { |
| | | cBuff = Searcher.loadContentFromFile(dbPath); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("RegionUtilsåå§å失败ï¼åå ï¼ä»ip2region.xdbæä»¶å è½½å
容失败ï¼" + e.getMessage()); |
| | | } |
| | | // 2ã使ç¨ä¸è¿°ç cBuff å建ä¸ä¸ªå®å
¨åºäºå
åçæ¥è¯¢å¯¹è±¡ã |
| | | try { |
| | | SEARCHER = Searcher.newWithBuffer(cBuff); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("RegionUtilsåå§å失败ï¼åå ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®IPå°å离线è·ååå¸ |
| | | */ |
| | | public static String getCityInfo(String ip) { |
| | | try { |
| | | ip = ip.trim(); |
| | | // 3ãæ§è¡æ¥è¯¢ |
| | | String region = SEARCHER.search(ip); |
| | | return region.replace("0|", "").replace("|0", ""); |
| | | } catch (Exception e) { |
| | | log.error("IPå°å离线è·ååå¸å¼å¸¸ {}", ip); |
| | | return "æªç¥"; |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.reflect; |
| | | |
| | | import cn.hutool.core.util.ReflectUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.lang.reflect.Method; |
| | | |
| | | /** |
| | | * åå°å·¥å
·ç±». æä¾è°ç¨getter/setteræ¹æ³, 访é®ç§æåé, è°ç¨ç§ææ¹æ³, è·åæ³åç±»åClass, 被AOPè¿ççå®ç±»çå·¥å
·å½æ°. |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SuppressWarnings("rawtypes") |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class ReflectUtils extends ReflectUtil { |
| | | |
| | | private static final String SETTER_PREFIX = "set"; |
| | | |
| | | private static final String GETTER_PREFIX = "get"; |
| | | |
| | | /** |
| | | * è°ç¨Getteræ¹æ³. |
| | | * æ¯æå¤çº§ï¼å¦ï¼å¯¹è±¡å.对象å.æ¹æ³ |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <E> E invokeGetter(Object obj, String propertyName) { |
| | | Object object = obj; |
| | | for (String name : StringUtils.split(propertyName, ".")) { |
| | | String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); |
| | | object = invoke(object, getterMethodName); |
| | | } |
| | | return (E) object; |
| | | } |
| | | |
| | | /** |
| | | * è°ç¨Setteræ¹æ³, ä»
å¹é
æ¹æ³åã |
| | | * æ¯æå¤çº§ï¼å¦ï¼å¯¹è±¡å.对象å.æ¹æ³ |
| | | */ |
| | | public static <E> void invokeSetter(Object obj, String propertyName, E value) { |
| | | Object object = obj; |
| | | String[] names = StringUtils.split(propertyName, "."); |
| | | for (int i = 0; i < names.length; i++) { |
| | | if (i < names.length - 1) { |
| | | String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); |
| | | object = invoke(object, getterMethodName); |
| | | } else { |
| | | String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); |
| | | Method method = getMethodByName(object.getClass(), setterMethodName); |
| | | invoke(object, method, value); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.utils.sql; |
| | | |
| | | import org.dromara.common.core.exception.UtilException; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * sqlæä½å·¥å
·ç±» |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class SqlUtil { |
| | | |
| | | /** |
| | | * å®ä¹å¸¸ç¨ç sqlå
³é®å |
| | | */ |
| | | public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare "; |
| | | |
| | | /** |
| | | * ä»
æ¯æåæ¯ãæ°åãä¸å线ãç©ºæ ¼ãéå·ãå°æ°ç¹ï¼æ¯æå¤ä¸ªå段æåºï¼ |
| | | */ |
| | | public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; |
| | | |
| | | /** |
| | | * æ£æ¥å符ï¼é²æ¢æ³¨å
¥ç»è¿ |
| | | */ |
| | | public static String escapeOrderBySql(String value) { |
| | | if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { |
| | | throw new UtilException("åæ°ä¸ç¬¦åè§èï¼ä¸è½è¿è¡æ¥è¯¢"); |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | /** |
| | | * éªè¯ order by è¯æ³æ¯å¦ç¬¦åè§è |
| | | */ |
| | | public static boolean isValidOrderBySql(String value) { |
| | | return value.matches(SQL_PATTERN); |
| | | } |
| | | |
| | | /** |
| | | * SQLå
³é®åæ£æ¥ |
| | | */ |
| | | public static void filterKeyword(String value) { |
| | | if (StringUtils.isEmpty(value)) { |
| | | return; |
| | | } |
| | | String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); |
| | | for (String sqlKeyword : sqlKeywords) { |
| | | if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { |
| | | throw new UtilException("åæ°åå¨SQL注å
¥é£é©"); |
| | | } |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.validate; |
| | | |
| | | /** |
| | | * æ ¡éªåç» add |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface AddGroup { |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.validate; |
| | | |
| | | /** |
| | | * æ ¡éªåç» edit |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface EditGroup { |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.validate; |
| | | |
| | | /** |
| | | * æ ¡éªåç» query |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface QueryGroup { |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.xss; |
| | | |
| | | import jakarta.validation.Constraint; |
| | | import jakarta.validation.Payload; |
| | | import java.lang.annotation.ElementType; |
| | | import java.lang.annotation.Retention; |
| | | import java.lang.annotation.RetentionPolicy; |
| | | import java.lang.annotation.Target; |
| | | |
| | | /** |
| | | * èªå®ä¹xssæ ¡éªæ³¨è§£ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) |
| | | @Constraint(validatedBy = {XssValidator.class}) |
| | | public @interface Xss { |
| | | |
| | | String message() default "ä¸å
许任ä½èæ¬è¿è¡"; |
| | | |
| | | Class<?>[] groups() default {}; |
| | | |
| | | Class<? extends Payload>[] payload() default {}; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.core.xss; |
| | | |
| | | import cn.hutool.core.util.ReUtil; |
| | | import cn.hutool.http.HtmlUtil; |
| | | |
| | | import jakarta.validation.ConstraintValidator; |
| | | import jakarta.validation.ConstraintValidatorContext; |
| | | |
| | | /** |
| | | * èªå®ä¹xssæ ¡éªæ³¨è§£å®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class XssValidator implements ConstraintValidator<Xss, String> { |
| | | |
| | | @Override |
| | | public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { |
| | | return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.core.config.ApplicationConfig |
| | | com.ruoyi.common.core.config.AsyncConfig |
| | | com.ruoyi.common.core.config.RuoYiConfig |
| | | com.ruoyi.common.core.config.ThreadPoolConfig |
| | | com.ruoyi.common.core.config.ValidatorConfig |
| | | com.ruoyi.common.core.utils.SpringUtils |
| | | org.dromara.common.core.config.ApplicationConfig |
| | | org.dromara.common.core.config.AsyncConfig |
| | | org.dromara.common.core.config.RuoYiConfig |
| | | org.dromara.common.core.config.ThreadPoolConfig |
| | | org.dromara.common.core.config.ValidatorConfig |
| | | org.dromara.common.core.utils.SpringUtils |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.doc.config; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.doc.config.properties.SwaggerProperties; |
| | | import org.dromara.common.doc.handler.OpenApiHandler; |
| | | import io.swagger.v3.oas.models.OpenAPI; |
| | | import io.swagger.v3.oas.models.Paths; |
| | | import io.swagger.v3.oas.models.info.Info; |
| | | import io.swagger.v3.oas.models.security.SecurityRequirement; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springdoc.core.configuration.SpringDocConfiguration; |
| | | import org.springdoc.core.customizers.OpenApiBuilderCustomizer; |
| | | import org.springdoc.core.customizers.OpenApiCustomizer; |
| | | import org.springdoc.core.customizers.ServerBaseUrlCustomizer; |
| | | import org.springdoc.core.properties.SpringDocConfigProperties; |
| | | import org.springdoc.core.providers.JavadocProvider; |
| | | import org.springdoc.core.service.OpenAPIService; |
| | | import org.springdoc.core.service.SecurityService; |
| | | import org.springdoc.core.utils.PropertyResolverUtils; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.autoconfigure.web.ServerProperties; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * Swagger ææ¡£é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @AutoConfiguration(before = SpringDocConfiguration.class) |
| | | @EnableConfigurationProperties(SwaggerProperties.class) |
| | | @ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true) |
| | | public class SwaggerConfig { |
| | | |
| | | private final ServerProperties serverProperties; |
| | | |
| | | @Bean |
| | | @ConditionalOnMissingBean(OpenAPI.class) |
| | | public OpenAPI openApi(SwaggerProperties swaggerProperties) { |
| | | OpenAPI openApi = new OpenAPI(); |
| | | // ææ¡£åºæ¬ä¿¡æ¯ |
| | | SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo(); |
| | | Info info = convertInfo(infoProperties); |
| | | openApi.info(info); |
| | | // æ©å±ææ¡£ä¿¡æ¯ |
| | | openApi.externalDocs(swaggerProperties.getExternalDocs()); |
| | | openApi.tags(swaggerProperties.getTags()); |
| | | openApi.paths(swaggerProperties.getPaths()); |
| | | openApi.components(swaggerProperties.getComponents()); |
| | | Set<String> keySet = swaggerProperties.getComponents().getSecuritySchemes().keySet(); |
| | | List<SecurityRequirement> list = new ArrayList<>(); |
| | | SecurityRequirement securityRequirement = new SecurityRequirement(); |
| | | keySet.forEach(securityRequirement::addList); |
| | | list.add(securityRequirement); |
| | | openApi.security(list); |
| | | |
| | | return openApi; |
| | | } |
| | | |
| | | private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) { |
| | | Info info = new Info(); |
| | | info.setTitle(infoProperties.getTitle()); |
| | | info.setDescription(infoProperties.getDescription()); |
| | | info.setContact(infoProperties.getContact()); |
| | | info.setLicense(infoProperties.getLicense()); |
| | | info.setVersion(infoProperties.getVersion()); |
| | | return info; |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹ openapi å¤çå¨ |
| | | */ |
| | | @Bean |
| | | public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI, |
| | | SecurityService securityParser, |
| | | SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, |
| | | Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers, |
| | | Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) { |
| | | return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); |
| | | } |
| | | |
| | | /** |
| | | * 对已ç»çæå¥½ç OpenApi è¿è¡èªå®ä¹æä½ |
| | | */ |
| | | @Bean |
| | | public OpenApiCustomizer openApiCustomiser() { |
| | | String contextPath = serverProperties.getServlet().getContextPath(); |
| | | String finalContextPath; |
| | | if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) { |
| | | finalContextPath = ""; |
| | | } else { |
| | | finalContextPath = contextPath; |
| | | } |
| | | // 对ææè·¯å¾å¢å åç½®ä¸ä¸æè·¯å¾ |
| | | return openApi -> { |
| | | Paths oldPaths = openApi.getPaths(); |
| | | if (oldPaths instanceof PlusPaths) { |
| | | return; |
| | | } |
| | | PlusPaths newPaths = new PlusPaths(); |
| | | oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v)); |
| | | openApi.setPaths(newPaths); |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * åç¬ä½¿ç¨ä¸ä¸ªç±»ä¾¿äºå¤æ è§£å³springdocè·¯å¾æ¼æ¥éå¤é®é¢ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | static class PlusPaths extends Paths { |
| | | |
| | | public PlusPaths() { |
| | | super(); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.doc.config.properties; |
| | | |
| | | import io.swagger.v3.oas.models.Components; |
| | | import io.swagger.v3.oas.models.ExternalDocumentation; |
| | | import io.swagger.v3.oas.models.Paths; |
| | | import io.swagger.v3.oas.models.info.Contact; |
| | | import io.swagger.v3.oas.models.info.License; |
| | | import io.swagger.v3.oas.models.tags.Tag; |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.boot.context.properties.NestedConfigurationProperty; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * swagger é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "swagger") |
| | | public class SwaggerProperties { |
| | | |
| | | /** |
| | | * ææ¡£åºæ¬ä¿¡æ¯ |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private InfoProperties info = new InfoProperties(); |
| | | |
| | | /** |
| | | * æ©å±ææ¡£å°å |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private ExternalDocumentation externalDocs; |
| | | |
| | | /** |
| | | * æ ç¾ |
| | | */ |
| | | private List<Tag> tags = null; |
| | | |
| | | /** |
| | | * è·¯å¾ |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private Paths paths = null; |
| | | |
| | | /** |
| | | * ç»ä»¶ |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private Components components = null; |
| | | |
| | | /** |
| | | * <p> |
| | | * ææ¡£çåºç¡å±æ§ä¿¡æ¯ |
| | | * </p> |
| | | * |
| | | * @see io.swagger.v3.oas.models.info.Info |
| | | * |
| | | * ä¸ºäº springboot èªå¨ç产é
ç½®æç¤ºä¿¡æ¯ï¼æä»¥è¿éå¤å¶ä¸ä¸ªç±»åºæ¥ |
| | | */ |
| | | @Data |
| | | public static class InfoProperties { |
| | | |
| | | /** |
| | | * æ é¢ |
| | | */ |
| | | private String title = null; |
| | | |
| | | /** |
| | | * æè¿° |
| | | */ |
| | | private String description = null; |
| | | |
| | | /** |
| | | * èç³»äººä¿¡æ¯ |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private Contact contact = null; |
| | | |
| | | /** |
| | | * 许å¯è¯ |
| | | */ |
| | | @NestedConfigurationProperty |
| | | private License license = null; |
| | | |
| | | /** |
| | | * çæ¬ |
| | | */ |
| | | private String version = null; |
| | | |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.doc.handler; |
| | | |
| | | import cn.hutool.core.io.IoUtil; |
| | | import io.swagger.v3.core.jackson.TypeNameResolver; |
| | | import io.swagger.v3.core.util.AnnotationsUtils; |
| | | import io.swagger.v3.oas.annotations.tags.Tags; |
| | | import io.swagger.v3.oas.models.Components; |
| | | import io.swagger.v3.oas.models.OpenAPI; |
| | | import io.swagger.v3.oas.models.Operation; |
| | | import io.swagger.v3.oas.models.Paths; |
| | | import io.swagger.v3.oas.models.tags.Tag; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springdoc.core.customizers.OpenApiBuilderCustomizer; |
| | | import org.springdoc.core.customizers.ServerBaseUrlCustomizer; |
| | | import org.springdoc.core.properties.SpringDocConfigProperties; |
| | | import org.springdoc.core.providers.JavadocProvider; |
| | | import org.springdoc.core.service.OpenAPIService; |
| | | import org.springdoc.core.service.SecurityService; |
| | | import org.springdoc.core.utils.PropertyResolverUtils; |
| | | import org.springframework.context.ApplicationContext; |
| | | import org.springframework.core.annotation.AnnotatedElementUtils; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.method.HandlerMethod; |
| | | |
| | | import java.io.StringReader; |
| | | import java.lang.reflect.Method; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | import java.util.stream.Stream; |
| | | |
| | | /** |
| | | * èªå®ä¹ openapi å¤çå¨ |
| | | * 对æºç åè½è¿è¡ä¿®æ¹ å¢å¼ºä½¿ç¨ |
| | | */ |
| | | @Slf4j |
| | | @SuppressWarnings("all") |
| | | public class OpenApiHandler extends OpenAPIService { |
| | | |
| | | /** |
| | | * The Basic error controller. |
| | | */ |
| | | private static Class<?> basicErrorController; |
| | | |
| | | /** |
| | | * The Security parser. |
| | | */ |
| | | private final SecurityService securityParser; |
| | | |
| | | /** |
| | | * The Mappings map. |
| | | */ |
| | | private final Map<String, Object> mappingsMap = new HashMap<>(); |
| | | |
| | | /** |
| | | * The Springdoc tags. |
| | | */ |
| | | private final Map<HandlerMethod, Tag> springdocTags = new HashMap<>(); |
| | | |
| | | /** |
| | | * The Open api builder customisers. |
| | | */ |
| | | private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers; |
| | | |
| | | /** |
| | | * The server base URL customisers. |
| | | */ |
| | | private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers; |
| | | |
| | | /** |
| | | * The Spring doc config properties. |
| | | */ |
| | | private final SpringDocConfigProperties springDocConfigProperties; |
| | | |
| | | /** |
| | | * The Cached open api map. |
| | | */ |
| | | private final Map<String, OpenAPI> cachedOpenAPI = new HashMap<>(); |
| | | |
| | | /** |
| | | * The Property resolver utils. |
| | | */ |
| | | private final PropertyResolverUtils propertyResolverUtils; |
| | | |
| | | /** |
| | | * The javadoc provider. |
| | | */ |
| | | private final Optional<JavadocProvider> javadocProvider; |
| | | |
| | | /** |
| | | * The Context. |
| | | */ |
| | | private ApplicationContext context; |
| | | |
| | | /** |
| | | * The Open api. |
| | | */ |
| | | private OpenAPI openAPI; |
| | | |
| | | /** |
| | | * The Is servers present. |
| | | */ |
| | | private boolean isServersPresent; |
| | | |
| | | /** |
| | | * The Server base url. |
| | | */ |
| | | private String serverBaseUrl; |
| | | |
| | | /** |
| | | * Instantiates a new Open api builder. |
| | | * |
| | | * @param openAPI the open api |
| | | * @param securityParser the security parser |
| | | * @param springDocConfigProperties the spring doc config properties |
| | | * @param propertyResolverUtils the property resolver utils |
| | | * @param openApiBuilderCustomizers the open api builder customisers |
| | | * @param serverBaseUrlCustomizers the server base url customizers |
| | | * @param javadocProvider the javadoc provider |
| | | */ |
| | | public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser, |
| | | SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, |
| | | Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers, |
| | | Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers, |
| | | Optional<JavadocProvider> javadocProvider) { |
| | | super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); |
| | | if (openAPI.isPresent()) { |
| | | this.openAPI = openAPI.get(); |
| | | if (this.openAPI.getComponents() == null) |
| | | this.openAPI.setComponents(new Components()); |
| | | if (this.openAPI.getPaths() == null) |
| | | this.openAPI.setPaths(new Paths()); |
| | | if (!CollectionUtils.isEmpty(this.openAPI.getServers())) |
| | | this.isServersPresent = true; |
| | | } |
| | | this.propertyResolverUtils = propertyResolverUtils; |
| | | this.securityParser = securityParser; |
| | | this.springDocConfigProperties = springDocConfigProperties; |
| | | this.openApiBuilderCustomisers = openApiBuilderCustomizers; |
| | | this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; |
| | | this.javadocProvider = javadocProvider; |
| | | if (springDocConfigProperties.isUseFqn()) |
| | | TypeNameResolver.std.setUseFqn(true); |
| | | } |
| | | |
| | | @Override |
| | | public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) { |
| | | |
| | | Set<Tag> tags = new HashSet<>(); |
| | | Set<String> tagsStr = new HashSet<>(); |
| | | |
| | | buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); |
| | | buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); |
| | | |
| | | if (!CollectionUtils.isEmpty(tagsStr)) |
| | | tagsStr = tagsStr.stream() |
| | | .map(str -> propertyResolverUtils.resolve(str, locale)) |
| | | .collect(Collectors.toSet()); |
| | | |
| | | if (springdocTags.containsKey(handlerMethod)) { |
| | | io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod); |
| | | tagsStr.add(tag.getName()); |
| | | if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { |
| | | openAPI.addTagsItem(tag); |
| | | } |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(tagsStr)) { |
| | | if (CollectionUtils.isEmpty(operation.getTags())) |
| | | operation.setTags(new ArrayList<>(tagsStr)); |
| | | else { |
| | | Set<String> operationTagsSet = new HashSet<>(operation.getTags()); |
| | | operationTagsSet.addAll(tagsStr); |
| | | operation.getTags().clear(); |
| | | operation.getTags().addAll(operationTagsSet); |
| | | } |
| | | } |
| | | |
| | | if (isAutoTagClasses(operation)) { |
| | | |
| | | |
| | | if (javadocProvider.isPresent()) { |
| | | String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType()); |
| | | if (StringUtils.isNotBlank(description)) { |
| | | io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag(); |
| | | |
| | | // èªå®ä¹é¨å ä¿®æ¹ä½¿ç¨java注éå½tagå |
| | | List<String> list = IoUtil.readLines(new StringReader(description), new ArrayList<>()); |
| | | // tag.setName(tagAutoName); |
| | | tag.setName(list.get(0)); |
| | | operation.addTagsItem(list.get(0)); |
| | | |
| | | tag.setDescription(description); |
| | | if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { |
| | | openAPI.addTagsItem(tag); |
| | | } |
| | | } |
| | | } else { |
| | | String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName()); |
| | | operation.addTagsItem(tagAutoName); |
| | | } |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(tags)) { |
| | | // Existing tags |
| | | List<io.swagger.v3.oas.models.tags.Tag> openApiTags = openAPI.getTags(); |
| | | if (!CollectionUtils.isEmpty(openApiTags)) |
| | | tags.addAll(openApiTags); |
| | | openAPI.setTags(new ArrayList<>(tags)); |
| | | } |
| | | |
| | | // Handle SecurityRequirement at operation level |
| | | io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser |
| | | .getSecurityRequirements(handlerMethod); |
| | | if (securityRequirements != null) { |
| | | if (securityRequirements.length == 0) |
| | | operation.setSecurity(Collections.emptyList()); |
| | | else |
| | | securityParser.buildSecurityRequirement(securityRequirements, operation); |
| | | } |
| | | |
| | | return operation; |
| | | } |
| | | |
| | | private void buildTagsFromMethod(Method method, Set<io.swagger.v3.oas.models.tags.Tag> tags, Set<String> tagsStr, Locale locale) { |
| | | // method tags |
| | | Set<Tags> tagsSet = AnnotatedElementUtils |
| | | .findAllMergedAnnotations(method, Tags.class); |
| | | Set<io.swagger.v3.oas.annotations.tags.Tag> methodTags = tagsSet.stream() |
| | | .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()); |
| | | methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class)); |
| | | if (!CollectionUtils.isEmpty(methodTags)) { |
| | | tagsStr.addAll(methodTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toSet())); |
| | | List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags); |
| | | addTags(allTags, tags, locale); |
| | | } |
| | | } |
| | | |
| | | private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<io.swagger.v3.oas.models.tags.Tag> tags, Locale locale) { |
| | | Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optionalTagSet = AnnotationsUtils |
| | | .getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true); |
| | | optionalTagSet.ifPresent(tagsSet -> { |
| | | tagsSet.forEach(tag -> { |
| | | tag.name(propertyResolverUtils.resolve(tag.getName(), locale)); |
| | | tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale)); |
| | | if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName()))) |
| | | tags.add(tag); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.doc.config.SwaggerConfig |
| | | org.dromara.common.doc.config.SwaggerConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | <dependencies> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.annotation; |
| | | |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * åæ®µå 坿³¨è§£ |
| | | * |
| | | * @author è马 |
| | | */ |
| | | @Documented |
| | | @Inherited |
| | | @Target({ElementType.FIELD}) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | public @interface EncryptField { |
| | | |
| | | /** |
| | | * å å¯ç®æ³ |
| | | */ |
| | | AlgorithmType algorithm() default AlgorithmType.DEFAULT; |
| | | |
| | | /** |
| | | * ç§é¥ãAESãSM4éè¦ |
| | | */ |
| | | String password() default ""; |
| | | |
| | | /** |
| | | * å
¬é¥ãRSAãSM2éè¦ |
| | | */ |
| | | String publicKey() default ""; |
| | | |
| | | /** |
| | | * å
¬é¥ãRSAãSM2éè¦ |
| | | */ |
| | | String privateKey() default ""; |
| | | |
| | | /** |
| | | * ç¼ç æ¹å¼ã对å å¯ç®æ³ä¸ºBASE64çä¸èµ·ä½ç¨ |
| | | */ |
| | | EncodeType encode() default EncodeType.DEFAULT; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.config; |
| | | |
| | | import org.dromara.common.encrypt.core.EncryptorManager; |
| | | import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor; |
| | | import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor; |
| | | import org.dromara.common.encrypt.properties.EncryptorProperties; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | /** |
| | | * å è§£å¯é
ç½® |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(EncryptorProperties.class) |
| | | @ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") |
| | | public class EncryptorAutoConfiguration { |
| | | |
| | | @Autowired |
| | | private EncryptorProperties properties; |
| | | |
| | | @Bean |
| | | public EncryptorManager encryptorManager() { |
| | | return new EncryptorManager(); |
| | | } |
| | | |
| | | @Bean |
| | | public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) { |
| | | return new MybatisEncryptInterceptor(encryptorManager, properties); |
| | | } |
| | | |
| | | @Bean |
| | | public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { |
| | | return new MybatisDecryptInterceptor(encryptorManager, properties); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core; |
| | | |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * å å¯ä¸ä¸æ ç¨äºencryptorä¼ éå¿
è¦çåæ°ã |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Data |
| | | public class EncryptContext { |
| | | |
| | | /** |
| | | * é»è®¤ç®æ³ |
| | | */ |
| | | private AlgorithmType algorithm; |
| | | |
| | | /** |
| | | * å®å
¨ç§é¥ |
| | | */ |
| | | private String password; |
| | | |
| | | /** |
| | | * å
¬é¥ |
| | | */ |
| | | private String publicKey; |
| | | |
| | | /** |
| | | * ç§é¥ |
| | | */ |
| | | private String privateKey; |
| | | |
| | | /** |
| | | * ç¼ç æ¹å¼ï¼base64/hex |
| | | */ |
| | | private EncodeType encode; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core; |
| | | |
| | | import cn.hutool.core.util.ReflectUtil; |
| | | import org.dromara.common.encrypt.annotation.EncryptField; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.Arrays; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * å å¯ç®¡çç±» |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Slf4j |
| | | public class EncryptorManager { |
| | | |
| | | /** |
| | | * ç¼åå å¯å¨ |
| | | */ |
| | | Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * ç±»å å¯å段ç¼å |
| | | */ |
| | | Map<Class<?>, Set<Field>> fieldCache = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * è·åç±»å å¯å段ç¼å |
| | | */ |
| | | public Set<Field> getFieldCache(Class<?> sourceClazz) { |
| | | return fieldCache.computeIfAbsent(sourceClazz, clazz -> { |
| | | Field[] declaredFields = clazz.getDeclaredFields(); |
| | | Set<Field> fieldSet = Arrays.stream(declaredFields).filter(field -> |
| | | field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) |
| | | .collect(Collectors.toSet()); |
| | | for (Field field : fieldSet) { |
| | | field.setAccessible(true); |
| | | } |
| | | return fieldSet; |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 注åå 坿§è¡è
å°ç¼å |
| | | * |
| | | * @param encryptContext å 坿§è¡è
éè¦çç¸å
³é
ç½®åæ° |
| | | */ |
| | | public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { |
| | | if (encryptorMap.containsKey(encryptContext)) { |
| | | return encryptorMap.get(encryptContext); |
| | | } |
| | | IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); |
| | | encryptorMap.put(encryptContext, encryptor); |
| | | return encryptor; |
| | | } |
| | | |
| | | /** |
| | | * ç§»é¤ç¼åä¸çå 坿§è¡è
|
| | | * |
| | | * @param encryptContext å 坿§è¡è
éè¦çç¸å
³é
ç½®åæ° |
| | | */ |
| | | public void removeEncryptor(EncryptContext encryptContext) { |
| | | this.encryptorMap.remove(encryptContext); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®é
ç½®è¿è¡å å¯ãä¼è¿è¡æ¬å°ç¼å对åºçç®æ³å对åºçç§é¥ä¿¡æ¯ã |
| | | * |
| | | * @param value å¾
å å¯çå¼ |
| | | * @param encryptContext å å¯ç¸å
³çé
ç½®ä¿¡æ¯ |
| | | */ |
| | | public String encrypt(String value, EncryptContext encryptContext) { |
| | | IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); |
| | | return encryptor.encrypt(value, encryptContext.getEncode()); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®é
ç½®è¿è¡è§£å¯ |
| | | * |
| | | * @param value å¾
è§£å¯çå¼ |
| | | * @param encryptContext å å¯ç¸å
³çé
ç½®ä¿¡æ¯ |
| | | */ |
| | | public String decrypt(String value, EncryptContext encryptContext) { |
| | | IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); |
| | | return encryptor.decrypt(value); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core; |
| | | |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | /** |
| | | * å è§£è
|
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public interface IEncryptor { |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | AlgorithmType algorithm(); |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | * @return å å¯åçå符串 |
| | | */ |
| | | String encrypt(String value, EncodeType encodeType); |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @return è§£å¯åçå符串 |
| | | */ |
| | | String decrypt(String value); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.core.IEncryptor; |
| | | |
| | | /** |
| | | * ææå 坿§è¡è
çåºç±» |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public abstract class AbstractEncryptor implements IEncryptor { |
| | | |
| | | public AbstractEncryptor(EncryptContext context) { |
| | | // ç¨æ·é
ç½®æ ¡éªä¸é
置注å
¥ |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.crypto.SecureUtil; |
| | | import cn.hutool.crypto.symmetric.AES; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | import java.nio.charset.StandardCharsets; |
| | | |
| | | /** |
| | | * AESç®æ³å®ç° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public class AesEncryptor extends AbstractEncryptor { |
| | | |
| | | private final AES aes; |
| | | |
| | | public AesEncryptor(EncryptContext context) { |
| | | super(context); |
| | | String password = context.getPassword(); |
| | | if (StrUtil.isBlank(password)) { |
| | | throw new IllegalArgumentException("AES没æè·å¾ç§é¥ä¿¡æ¯"); |
| | | } |
| | | // aesç®æ³çç§é¥è¦æ±æ¯16ä½ã24ä½ã32ä½ |
| | | int[] array = {16, 24, 32}; |
| | | if (!ArrayUtil.contains(array, password.length())) { |
| | | throw new IllegalArgumentException("AESç§é¥é¿åº¦åºè¯¥ä¸º16ä½ã24ä½ã32ä½ï¼å®é
为" + password.length() + "ä½"); |
| | | } |
| | | aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8)); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | @Override |
| | | public AlgorithmType algorithm() { |
| | | return AlgorithmType.AES; |
| | | } |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | */ |
| | | @Override |
| | | public String encrypt(String value, EncodeType encodeType) { |
| | | if (encodeType == EncodeType.HEX) { |
| | | return aes.encryptHex(value); |
| | | } else { |
| | | return aes.encryptBase64(value); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | */ |
| | | @Override |
| | | public String decrypt(String value) { |
| | | return this.aes.decryptStr(value); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import cn.hutool.core.codec.Base64; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | /** |
| | | * Base64ç®æ³å®ç° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public class Base64Encryptor extends AbstractEncryptor { |
| | | |
| | | public Base64Encryptor(EncryptContext context) { |
| | | super(context); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | @Override |
| | | public AlgorithmType algorithm() { |
| | | return AlgorithmType.BASE64; |
| | | } |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | */ |
| | | @Override |
| | | public String encrypt(String value, EncodeType encodeType) { |
| | | return Base64.encode(value); |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | */ |
| | | @Override |
| | | public String decrypt(String value) { |
| | | return Base64.decodeStr(value); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import cn.hutool.core.codec.Base64; |
| | | import cn.hutool.crypto.SecureUtil; |
| | | import cn.hutool.crypto.asymmetric.KeyType; |
| | | import cn.hutool.crypto.asymmetric.RSA; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | |
| | | /** |
| | | * RSAç®æ³å®ç° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public class RsaEncryptor extends AbstractEncryptor { |
| | | |
| | | private final RSA rsa; |
| | | |
| | | public RsaEncryptor(EncryptContext context) { |
| | | super(context); |
| | | String privateKey = context.getPrivateKey(); |
| | | String publicKey = context.getPublicKey(); |
| | | if (StringUtils.isAnyEmpty(privateKey, publicKey)) { |
| | | throw new IllegalArgumentException("RSAå
¬ç§é¥åéè¦æä¾ï¼å
¬é¥å å¯ï¼ç§é¥è§£å¯ã"); |
| | | } |
| | | this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey)); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | @Override |
| | | public AlgorithmType algorithm() { |
| | | return AlgorithmType.RSA; |
| | | } |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | */ |
| | | @Override |
| | | public String encrypt(String value, EncodeType encodeType) { |
| | | if (encodeType == EncodeType.HEX) { |
| | | return rsa.encryptHex(value, KeyType.PublicKey); |
| | | } else { |
| | | return rsa.encryptBase64(value, KeyType.PublicKey); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | */ |
| | | @Override |
| | | public String decrypt(String value) { |
| | | return this.rsa.decryptStr(value, KeyType.PrivateKey); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import cn.hutool.core.codec.Base64; |
| | | import cn.hutool.crypto.SmUtil; |
| | | import cn.hutool.crypto.asymmetric.KeyType; |
| | | import cn.hutool.crypto.asymmetric.SM2; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | /** |
| | | * sm2ç®æ³å®ç° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public class Sm2Encryptor extends AbstractEncryptor { |
| | | |
| | | private final SM2 sm2; |
| | | |
| | | public Sm2Encryptor(EncryptContext context) { |
| | | super(context); |
| | | String privateKey = context.getPrivateKey(); |
| | | String publicKey = context.getPublicKey(); |
| | | if (StringUtils.isAnyEmpty(privateKey, publicKey)) { |
| | | throw new IllegalArgumentException("SM2å
¬ç§é¥åéè¦æä¾ï¼å
¬é¥å å¯ï¼ç§é¥è§£å¯ã"); |
| | | } |
| | | this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey)); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | @Override |
| | | public AlgorithmType algorithm() { |
| | | return AlgorithmType.SM2; |
| | | } |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | */ |
| | | @Override |
| | | public String encrypt(String value, EncodeType encodeType) { |
| | | if (encodeType == EncodeType.HEX) { |
| | | return sm2.encryptHex(value, KeyType.PublicKey); |
| | | } else { |
| | | return sm2.encryptBase64(value, KeyType.PublicKey); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | */ |
| | | @Override |
| | | public String decrypt(String value) { |
| | | return this.sm2.decryptStr(value, KeyType.PrivateKey); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.core.encryptor; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.crypto.SmUtil; |
| | | import cn.hutool.crypto.symmetric.SM4; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | |
| | | import java.nio.charset.StandardCharsets; |
| | | |
| | | /** |
| | | * sm4ç®æ³å®ç° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public class Sm4Encryptor extends AbstractEncryptor { |
| | | |
| | | private final SM4 sm4; |
| | | |
| | | public Sm4Encryptor(EncryptContext context) { |
| | | super(context); |
| | | String password = context.getPassword(); |
| | | if (StrUtil.isBlank(password)) { |
| | | throw new IllegalArgumentException("SM4没æè·å¾ç§é¥ä¿¡æ¯"); |
| | | } |
| | | // sm4ç®æ³çç§é¥è¦æ±æ¯16ä½é¿åº¦ |
| | | if (16 != password.length()) { |
| | | throw new IllegalArgumentException("SM4ç§é¥é¿åº¦åºè¯¥ä¸º16ä½ï¼å®é
为" + password.length() + "ä½"); |
| | | } |
| | | this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾å½åç®æ³ |
| | | */ |
| | | @Override |
| | | public AlgorithmType algorithm() { |
| | | return AlgorithmType.SM4; |
| | | } |
| | | |
| | | /** |
| | | * å å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | * @param encodeType å å¯åçç¼ç æ ¼å¼ |
| | | */ |
| | | @Override |
| | | public String encrypt(String value, EncodeType encodeType) { |
| | | if (encodeType == EncodeType.HEX) { |
| | | return sm4.encryptHex(value); |
| | | } else { |
| | | return sm4.encryptBase64(value); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯ |
| | | * |
| | | * @param value å¾
å å¯å符串 |
| | | */ |
| | | @Override |
| | | public String decrypt(String value) { |
| | | return this.sm4.decryptStr(value); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.enumd; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | import org.dromara.common.encrypt.core.encryptor.*; |
| | | |
| | | /** |
| | | * ç®æ³åç§° |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum AlgorithmType { |
| | | |
| | | /** |
| | | * é»è®¤èµ°ymlé
ç½® |
| | | */ |
| | | DEFAULT(null), |
| | | |
| | | /** |
| | | * base64 |
| | | */ |
| | | BASE64(Base64Encryptor.class), |
| | | |
| | | /** |
| | | * aes |
| | | */ |
| | | AES(AesEncryptor.class), |
| | | |
| | | /** |
| | | * rsa |
| | | */ |
| | | RSA(RsaEncryptor.class), |
| | | |
| | | /** |
| | | * sm2 |
| | | */ |
| | | SM2(Sm2Encryptor.class), |
| | | |
| | | /** |
| | | * sm4 |
| | | */ |
| | | SM4(Sm4Encryptor.class); |
| | | |
| | | private final Class<? extends AbstractEncryptor> clazz; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.enumd; |
| | | |
| | | /** |
| | | * ç¼ç ç±»å |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | public enum EncodeType { |
| | | |
| | | /** |
| | | * é»è®¤ä½¿ç¨ymlé
ç½® |
| | | */ |
| | | DEFAULT, |
| | | |
| | | /** |
| | | * base64ç¼ç |
| | | */ |
| | | BASE64, |
| | | |
| | | /** |
| | | * 16è¿å¶ç¼ç |
| | | */ |
| | | HEX; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.interceptor; |
| | | |
| | | import cn.hutool.core.collection.CollectionUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.encrypt.annotation.EncryptField; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.core.EncryptorManager; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | import org.dromara.common.encrypt.properties.EncryptorProperties; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.ibatis.executor.resultset.ResultSetHandler; |
| | | import org.apache.ibatis.plugin.*; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.sql.Statement; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * åºåè§£å¯æ¦æªå¨ |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Slf4j |
| | | @Intercepts({@Signature( |
| | | type = ResultSetHandler.class, |
| | | method = "handleResultSets", |
| | | args = {Statement.class}) |
| | | }) |
| | | @AllArgsConstructor |
| | | public class MybatisDecryptInterceptor implements Interceptor { |
| | | |
| | | private final EncryptorManager encryptorManager; |
| | | private final EncryptorProperties defaultProperties; |
| | | |
| | | @Override |
| | | public Object intercept(Invocation invocation) throws Throwable { |
| | | // è·åæ§è¡mysqlæ§è¡ç»æ |
| | | Object result = invocation.proceed(); |
| | | if (result == null) { |
| | | return null; |
| | | } |
| | | decryptHandler(result); |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * è§£å¯å¯¹è±¡ |
| | | * |
| | | * @param sourceObject å¾
å å¯å¯¹è±¡ |
| | | */ |
| | | private void decryptHandler(Object sourceObject) { |
| | | if (ObjectUtil.isNull(sourceObject)) { |
| | | return; |
| | | } |
| | | if (sourceObject instanceof Map<?, ?> map) { |
| | | new HashSet<>(map.values()).forEach(this::decryptHandler); |
| | | return; |
| | | } |
| | | if (sourceObject instanceof List<?> list) { |
| | | if(CollectionUtil.isEmpty(list)) { |
| | | return; |
| | | } |
| | | // å¤æç¬¬ä¸ä¸ªå
ç´ æ¯å¦å«ææ³¨è§£ãå¦ææ²¡æç´æ¥è¿åï¼æé«æç |
| | | Object firstItem = list.get(0); |
| | | if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { |
| | | return; |
| | | } |
| | | list.forEach(this::decryptHandler); |
| | | return; |
| | | } |
| | | Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass()); |
| | | try { |
| | | for (Field field : fields) { |
| | | field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("å¤çè§£å¯å段æ¶åºé", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åæ®µå¼è¿è¡å å¯ãéè¿åæ®µçæ¹æ³¨æ³¨åæ°çå å¯ç®æ³ |
| | | * |
| | | * @param value å¾
å å¯çå¼ |
| | | * @param field å¾
å å¯å段 |
| | | * @return å å¯åç»æ |
| | | */ |
| | | private String decryptField(String value, Field field) { |
| | | EncryptField encryptField = field.getAnnotation(EncryptField.class); |
| | | EncryptContext encryptContext = new EncryptContext(); |
| | | encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); |
| | | encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); |
| | | encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); |
| | | encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); |
| | | encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); |
| | | return this.encryptorManager.decrypt(value, encryptContext); |
| | | } |
| | | |
| | | @Override |
| | | public Object plugin(Object target) { |
| | | return Plugin.wrap(target, this); |
| | | } |
| | | |
| | | @Override |
| | | public void setProperties(Properties properties) { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.interceptor; |
| | | |
| | | import cn.hutool.core.collection.CollectionUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.encrypt.annotation.EncryptField; |
| | | import org.dromara.common.encrypt.core.EncryptContext; |
| | | import org.dromara.common.encrypt.core.EncryptorManager; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | import org.dromara.common.encrypt.properties.EncryptorProperties; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.ibatis.executor.parameter.ParameterHandler; |
| | | import org.apache.ibatis.plugin.Interceptor; |
| | | import org.apache.ibatis.plugin.Intercepts; |
| | | import org.apache.ibatis.plugin.Invocation; |
| | | import org.apache.ibatis.plugin.Signature; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.sql.PreparedStatement; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * å
¥åå 坿¦æªå¨ |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Slf4j |
| | | @Intercepts({@Signature( |
| | | type = ParameterHandler.class, |
| | | method = "setParameters", |
| | | args = {PreparedStatement.class}) |
| | | }) |
| | | @AllArgsConstructor |
| | | public class MybatisEncryptInterceptor implements Interceptor { |
| | | |
| | | private final EncryptorManager encryptorManager; |
| | | private final EncryptorProperties defaultProperties; |
| | | |
| | | @Override |
| | | public Object intercept(Invocation invocation) throws Throwable { |
| | | return invocation; |
| | | } |
| | | |
| | | @Override |
| | | public Object plugin(Object target) { |
| | | if (target instanceof ParameterHandler parameterHandler) { |
| | | // è¿è¡å å¯æä½ |
| | | Object parameterObject = parameterHandler.getParameterObject(); |
| | | if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { |
| | | this.encryptHandler(parameterObject); |
| | | } |
| | | } |
| | | return target; |
| | | } |
| | | |
| | | /** |
| | | * å å¯å¯¹è±¡ |
| | | * |
| | | * @param sourceObject å¾
å å¯å¯¹è±¡ |
| | | */ |
| | | private void encryptHandler(Object sourceObject) { |
| | | if (ObjectUtil.isNull(sourceObject)) { |
| | | return; |
| | | } |
| | | if (sourceObject instanceof Map<?, ?> map) { |
| | | new HashSet<>(map.values()).forEach(this::encryptHandler); |
| | | return; |
| | | } |
| | | if (sourceObject instanceof List<?> list) { |
| | | if(CollectionUtil.isEmpty(list)) { |
| | | return; |
| | | } |
| | | // å¤æç¬¬ä¸ä¸ªå
ç´ æ¯å¦å«ææ³¨è§£ãå¦ææ²¡æç´æ¥è¿åï¼æé«æç |
| | | Object firstItem = list.get(0); |
| | | if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { |
| | | return; |
| | | } |
| | | list.forEach(this::encryptHandler); |
| | | return; |
| | | } |
| | | Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass()); |
| | | try { |
| | | for (Field field : fields) { |
| | | field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("å¤çå å¯å段æ¶åºé", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åæ®µå¼è¿è¡å å¯ãéè¿åæ®µçæ¹æ³¨æ³¨åæ°çå å¯ç®æ³ |
| | | * |
| | | * @param value å¾
å å¯çå¼ |
| | | * @param field å¾
å å¯å段 |
| | | * @return å å¯åç»æ |
| | | */ |
| | | private String encryptField(String value, Field field) { |
| | | EncryptField encryptField = field.getAnnotation(EncryptField.class); |
| | | EncryptContext encryptContext = new EncryptContext(); |
| | | encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); |
| | | encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); |
| | | encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); |
| | | encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); |
| | | encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); |
| | | return this.encryptorManager.encrypt(value, encryptContext); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void setProperties(Properties properties) { |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.encrypt.properties; |
| | | |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import org.dromara.common.encrypt.enumd.EncodeType; |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * å è§£å¯å±æ§é
置类 |
| | | * |
| | | * @author è马 |
| | | * @version 4.6.0 |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "mybatis-encryptor") |
| | | public class EncryptorProperties { |
| | | |
| | | /** |
| | | * è¿æ»¤å¼å
³ |
| | | */ |
| | | private Boolean enable; |
| | | |
| | | /** |
| | | * é»è®¤ç®æ³ |
| | | */ |
| | | private AlgorithmType algorithm; |
| | | |
| | | /** |
| | | * å®å
¨ç§é¥ |
| | | */ |
| | | private String password; |
| | | |
| | | /** |
| | | * å
¬é¥ |
| | | */ |
| | | private String publicKey; |
| | | |
| | | /** |
| | | * ç§é¥ |
| | | */ |
| | | private String privateKey; |
| | | |
| | | /** |
| | | * ç¼ç æ¹å¼ï¼base64/hex |
| | | */ |
| | | private EncodeType encode; |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.encrypt.config.EncryptorAutoConfiguration |
| | | org.dromara.common.encrypt.config.EncryptorAutoConfiguration |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.annotation; |
| | | |
| | | import org.dromara.common.excel.core.CellMergeStrategy; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * excel ååå
æ ¼åå¹¶(åå¹¶åç¸å项) |
| | | * |
| | | * éæé
{@link CellMergeStrategy} çç¥ä½¿ç¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Target(ElementType.FIELD) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Inherited |
| | | public @interface CellMerge { |
| | | |
| | | /** |
| | | * col index |
| | | */ |
| | | int index() default -1; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.annotation; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * åå
¸æ ¼å¼å |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Target({ElementType.FIELD}) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Inherited |
| | | public @interface ExcelDictFormat { |
| | | |
| | | /** |
| | | * 妿æ¯åå
¸ç±»åï¼è¯·è®¾ç½®åå
¸çtypeå¼ (å¦: sys_user_sex) |
| | | */ |
| | | String dictType() default ""; |
| | | |
| | | /** |
| | | * 读åå
å®¹è½¬è¡¨è¾¾å¼ (å¦: 0=ç·,1=女,2=æªç¥) |
| | | */ |
| | | String readConverterExp() default ""; |
| | | |
| | | /** |
| | | * åé符ï¼è¯»åå符串ç»å
容 |
| | | */ |
| | | String separator() default StringUtils.SEPARATOR; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.annotation; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * æä¸¾æ ¼å¼å |
| | | * |
| | | * @author Liang |
| | | */ |
| | | @Target({ElementType.FIELD}) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Inherited |
| | | public @interface ExcelEnumFormat { |
| | | |
| | | /** |
| | | * åå
¸æä¸¾ç±»å |
| | | */ |
| | | Class<? extends Enum<?>> enumClass(); |
| | | |
| | | /** |
| | | * åå
¸æä¸¾ç±»ä¸å¯¹åºçcode屿§åç§°ï¼é»è®¤ä¸ºcode |
| | | */ |
| | | String codeField() default "code"; |
| | | |
| | | /** |
| | | * åå
¸æä¸¾ç±»ä¸å¯¹åºçtext屿§åç§°ï¼é»è®¤ä¸ºtext |
| | | */ |
| | | String textField() default "text"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.convert; |
| | | |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.alibaba.excel.converters.Converter; |
| | | import com.alibaba.excel.enums.CellDataTypeEnum; |
| | | import com.alibaba.excel.metadata.GlobalConfiguration; |
| | | import com.alibaba.excel.metadata.data.ReadCellData; |
| | | import com.alibaba.excel.metadata.data.WriteCellData; |
| | | import com.alibaba.excel.metadata.property.ExcelContentProperty; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * 大æ°å¼è½¬æ¢ |
| | | * Excel æ°å¼é¿åº¦ä½15ä½ å¤§äº15ä½çæ°å¼è½¬æ¢ä½å符串 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | public class ExcelBigNumberConvert implements Converter<Long> { |
| | | |
| | | @Override |
| | | public Class<Long> supportJavaTypeKey() { |
| | | return Long.class; |
| | | } |
| | | |
| | | @Override |
| | | public CellDataTypeEnum supportExcelTypeKey() { |
| | | return CellDataTypeEnum.STRING; |
| | | } |
| | | |
| | | @Override |
| | | public Long convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | return Convert.toLong(cellData.getData()); |
| | | } |
| | | |
| | | @Override |
| | | public WriteCellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | if (ObjectUtil.isNotNull(object)) { |
| | | String str = Convert.toStr(object); |
| | | if (str.length() > 15) { |
| | | return new WriteCellData<>(str); |
| | | } |
| | | } |
| | | WriteCellData<Object> cellData = new WriteCellData<>(new BigDecimal(object)); |
| | | cellData.setType(CellDataTypeEnum.NUMBER); |
| | | return cellData; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.convert; |
| | | |
| | | import cn.hutool.core.annotation.AnnotationUtil; |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.alibaba.excel.converters.Converter; |
| | | import com.alibaba.excel.enums.CellDataTypeEnum; |
| | | import com.alibaba.excel.metadata.GlobalConfiguration; |
| | | import com.alibaba.excel.metadata.data.ReadCellData; |
| | | import com.alibaba.excel.metadata.data.WriteCellData; |
| | | import com.alibaba.excel.metadata.property.ExcelContentProperty; |
| | | import org.dromara.common.excel.annotation.ExcelDictFormat; |
| | | import org.dromara.common.core.service.DictService; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.excel.utils.ExcelUtil; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.lang.reflect.Field; |
| | | |
| | | /** |
| | | * åå
¸æ ¼å¼å转æ¢å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | public class ExcelDictConvert implements Converter<Object> { |
| | | |
| | | @Override |
| | | public Class<Object> supportJavaTypeKey() { |
| | | return Object.class; |
| | | } |
| | | |
| | | @Override |
| | | public CellDataTypeEnum supportExcelTypeKey() { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | ExcelDictFormat anno = getAnnotation(contentProperty.getField()); |
| | | String type = anno.dictType(); |
| | | String label = cellData.getStringValue(); |
| | | String value; |
| | | if (StringUtils.isBlank(type)) { |
| | | value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); |
| | | } else { |
| | | value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); |
| | | } |
| | | return Convert.convert(contentProperty.getField().getType(), value); |
| | | } |
| | | |
| | | @Override |
| | | public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | if (ObjectUtil.isNull(object)) { |
| | | return new WriteCellData<>(""); |
| | | } |
| | | ExcelDictFormat anno = getAnnotation(contentProperty.getField()); |
| | | String type = anno.dictType(); |
| | | String value = Convert.toStr(object); |
| | | String label; |
| | | if (StringUtils.isBlank(type)) { |
| | | label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); |
| | | } else { |
| | | label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); |
| | | } |
| | | return new WriteCellData<>(label); |
| | | } |
| | | |
| | | private ExcelDictFormat getAnnotation(Field field) { |
| | | return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.convert; |
| | | |
| | | import cn.hutool.core.annotation.AnnotationUtil; |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.alibaba.excel.converters.Converter; |
| | | import com.alibaba.excel.enums.CellDataTypeEnum; |
| | | import com.alibaba.excel.metadata.GlobalConfiguration; |
| | | import com.alibaba.excel.metadata.data.ReadCellData; |
| | | import com.alibaba.excel.metadata.data.WriteCellData; |
| | | import com.alibaba.excel.metadata.property.ExcelContentProperty; |
| | | import org.dromara.common.core.utils.reflect.ReflectUtils; |
| | | import org.dromara.common.excel.annotation.ExcelEnumFormat; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æä¸¾æ ¼å¼å转æ¢å¤ç |
| | | * |
| | | * @author Liang |
| | | */ |
| | | @Slf4j |
| | | public class ExcelEnumConvert implements Converter<Object> { |
| | | |
| | | @Override |
| | | public Class<Object> supportJavaTypeKey() { |
| | | return Object.class; |
| | | } |
| | | |
| | | @Override |
| | | public CellDataTypeEnum supportExcelTypeKey() { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | Object codeValue = cellData.getData(); |
| | | // 妿æ¯ç©ºå¼ |
| | | if (ObjectUtil.isNull(codeValue)) { |
| | | return null; |
| | | } |
| | | Map<Object, String> enumValueMap = beforeConvert(contentProperty); |
| | | String textValue = enumValueMap.get(codeValue); |
| | | return Convert.convert(contentProperty.getField().getType(), textValue); |
| | | } |
| | | |
| | | @Override |
| | | public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { |
| | | if (ObjectUtil.isNull(object)) { |
| | | return new WriteCellData<>(""); |
| | | } |
| | | Map<Object, String> enumValueMap = beforeConvert(contentProperty); |
| | | String value = Convert.toStr(enumValueMap.get(object), ""); |
| | | return new WriteCellData<>(value); |
| | | } |
| | | |
| | | private Map<Object, String> beforeConvert(ExcelContentProperty contentProperty) { |
| | | ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); |
| | | Map<Object, String> enumValueMap = new HashMap<>(); |
| | | Enum<?>[] enumConstants = anno.enumClass().getEnumConstants(); |
| | | for (Enum<?> enumConstant : enumConstants) { |
| | | Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); |
| | | String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); |
| | | enumValueMap.put(codeValue, textValue); |
| | | } |
| | | return enumValueMap; |
| | | } |
| | | |
| | | private ExcelEnumFormat getAnnotation(Field field) { |
| | | return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.core; |
| | | |
| | | import com.alibaba.excel.metadata.Head; |
| | | import com.alibaba.excel.write.merge.AbstractMergeStrategy; |
| | | import org.dromara.common.excel.annotation.CellMerge; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.SneakyThrows; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.lang.reflect.Method; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * åå¼éå¤åå¹¶çç¥ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | @Slf4j |
| | | public class CellMergeStrategy extends AbstractMergeStrategy { |
| | | |
| | | private List<?> list; |
| | | private boolean hasTitle; |
| | | |
| | | @Override |
| | | protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { |
| | | List<CellRangeAddress> cellList = handle(list, hasTitle); |
| | | // judge the list is not null |
| | | if (CollectionUtils.isNotEmpty(cellList)) { |
| | | // the judge is necessary |
| | | if (cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) { |
| | | for (CellRangeAddress item : cellList) { |
| | | sheet.addMergedRegion(item); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @SneakyThrows |
| | | private static List<CellRangeAddress> handle(List<?> list, boolean hasTitle) { |
| | | List<CellRangeAddress> cellList = new ArrayList<>(); |
| | | if (CollectionUtils.isEmpty(list)) { |
| | | return cellList; |
| | | } |
| | | Class<?> clazz = list.get(0).getClass(); |
| | | Field[] fields = clazz.getDeclaredFields(); |
| | | // ææ³¨è§£çåæ®µ |
| | | List<Field> mergeFields = new ArrayList<>(); |
| | | List<Integer> mergeFieldsIndex = new ArrayList<>(); |
| | | for (int i = 0; i < fields.length; i++) { |
| | | Field field = fields[i]; |
| | | if (field.isAnnotationPresent(CellMerge.class)) { |
| | | CellMerge cm = field.getAnnotation(CellMerge.class); |
| | | mergeFields.add(field); |
| | | mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); |
| | | } |
| | | } |
| | | // è¡åå¹¶å¼å§ä¸æ |
| | | int rowIndex = hasTitle ? 1 : 0; |
| | | Map<Field, RepeatCell> map = new HashMap<>(); |
| | | // çæä¸¤ä¸¤åå¹¶åå
æ ¼ |
| | | for (int i = 0; i < list.size(); i++) { |
| | | for (int j = 0; j < mergeFields.size(); j++) { |
| | | Field field = mergeFields.get(j); |
| | | String name = field.getName(); |
| | | String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); |
| | | Method readMethod = clazz.getMethod(methodName); |
| | | Object val = readMethod.invoke(list.get(i)); |
| | | |
| | | int colNum = mergeFieldsIndex.get(j); |
| | | if (!map.containsKey(field)) { |
| | | map.put(field, new RepeatCell(val, i)); |
| | | } else { |
| | | RepeatCell repeatCell = map.get(field); |
| | | Object cellValue = repeatCell.getValue(); |
| | | if (cellValue == null || "".equals(cellValue)) { |
| | | // 空å¼è·³è¿ä¸åå¹¶ |
| | | continue; |
| | | } |
| | | if (!cellValue.equals(val)) { |
| | | if (i - repeatCell.getCurrent() > 1) { |
| | | cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); |
| | | } |
| | | map.put(field, new RepeatCell(val, i)); |
| | | } else if (i == list.size() - 1) { |
| | | if (i > repeatCell.getCurrent()) { |
| | | cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return cellList; |
| | | } |
| | | |
| | | @Data |
| | | @AllArgsConstructor |
| | | static class RepeatCell { |
| | | |
| | | private Object value; |
| | | |
| | | private int current; |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.core; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.alibaba.excel.context.AnalysisContext; |
| | | import com.alibaba.excel.event.AnalysisEventListener; |
| | | import com.alibaba.excel.exception.ExcelAnalysisException; |
| | | import com.alibaba.excel.exception.ExcelDataConvertException; |
| | | import org.dromara.common.core.utils.StreamUtils; |
| | | import org.dromara.common.core.utils.ValidatorUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import jakarta.validation.ConstraintViolation; |
| | | import jakarta.validation.ConstraintViolationException; |
| | | import lombok.NoArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * Excel 导å
¥çå¬ |
| | | * |
| | | * @author Yjoioooo |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @NoArgsConstructor |
| | | public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> { |
| | | |
| | | /** |
| | | * æ¯å¦Validatoræ£éªï¼é»è®¤ä¸ºæ¯ |
| | | */ |
| | | private Boolean isValidate = Boolean.TRUE; |
| | | |
| | | /** |
| | | * excel è¡¨å¤´æ°æ® |
| | | */ |
| | | private Map<Integer, String> headMap; |
| | | |
| | | /** |
| | | * 导å
¥åæ§ |
| | | */ |
| | | private ExcelResult<T> excelResult; |
| | | |
| | | public DefaultExcelListener(boolean isValidate) { |
| | | this.excelResult = new DefautExcelResult<>(); |
| | | this.isValidate = isValidate; |
| | | } |
| | | |
| | | /** |
| | | * å¤çå¼å¸¸ |
| | | * |
| | | * @param exception ExcelDataConvertException |
| | | * @param context Excel ä¸ä¸æ |
| | | */ |
| | | @Override |
| | | public void onException(Exception exception, AnalysisContext context) throws Exception { |
| | | String errMsg = null; |
| | | if (exception instanceof ExcelDataConvertException excelDataConvertException) { |
| | | // å¦ææ¯æä¸ä¸ªåå
æ ¼ç转æ¢å¼å¸¸ è½è·åå°å
·ä½è¡å· |
| | | Integer rowIndex = excelDataConvertException.getRowIndex(); |
| | | Integer columnIndex = excelDataConvertException.getColumnIndex(); |
| | | errMsg = StrUtil.format("第{}è¡-第{}å-表头{}: è§£æå¼å¸¸<br/>", |
| | | rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); |
| | | if (log.isDebugEnabled()) { |
| | | log.error(errMsg); |
| | | } |
| | | } |
| | | if (exception instanceof ConstraintViolationException constraintViolationException) { |
| | | Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations(); |
| | | String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); |
| | | errMsg = StrUtil.format("第{}è¡æ°æ®æ ¡éªå¼å¸¸: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); |
| | | if (log.isDebugEnabled()) { |
| | | log.error(errMsg); |
| | | } |
| | | } |
| | | excelResult.getErrorList().add(errMsg); |
| | | throw new ExcelAnalysisException(errMsg); |
| | | } |
| | | |
| | | @Override |
| | | public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { |
| | | this.headMap = headMap; |
| | | log.debug("è§£æå°ä¸æ¡è¡¨å¤´æ°æ®: {}", JsonUtils.toJsonString(headMap)); |
| | | } |
| | | |
| | | @Override |
| | | public void invoke(T data, AnalysisContext context) { |
| | | if (isValidate) { |
| | | ValidatorUtils.validate(data); |
| | | } |
| | | excelResult.getList().add(data); |
| | | } |
| | | |
| | | @Override |
| | | public void doAfterAllAnalysed(AnalysisContext context) { |
| | | log.debug("æææ°æ®è§£æå®æï¼"); |
| | | } |
| | | |
| | | @Override |
| | | public ExcelResult<T> getExcelResult() { |
| | | return excelResult; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.core; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import lombok.Setter; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * é»è®¤excelè¿å对象 |
| | | * |
| | | * @author Yjoioooo |
| | | * @author Lion Li |
| | | */ |
| | | public class DefautExcelResult<T> implements ExcelResult<T> { |
| | | |
| | | /** |
| | | * æ°æ®å¯¹è±¡list |
| | | */ |
| | | @Setter |
| | | private List<T> list; |
| | | |
| | | /** |
| | | * é误信æ¯å表 |
| | | */ |
| | | @Setter |
| | | private List<String> errorList; |
| | | |
| | | public DefautExcelResult() { |
| | | this.list = new ArrayList<>(); |
| | | this.errorList = new ArrayList<>(); |
| | | } |
| | | |
| | | public DefautExcelResult(List<T> list, List<String> errorList) { |
| | | this.list = list; |
| | | this.errorList = errorList; |
| | | } |
| | | |
| | | public DefautExcelResult(ExcelResult<T> excelResult) { |
| | | this.list = excelResult.getList(); |
| | | this.errorList = excelResult.getErrorList(); |
| | | } |
| | | |
| | | @Override |
| | | public List<T> getList() { |
| | | return list; |
| | | } |
| | | |
| | | @Override |
| | | public List<String> getErrorList() { |
| | | return errorList; |
| | | } |
| | | |
| | | /** |
| | | * è·å导å
¥åæ§ |
| | | * |
| | | * @return 导å
¥åæ§ |
| | | */ |
| | | @Override |
| | | public String getAnalysis() { |
| | | int successCount = list.size(); |
| | | int errorCount = errorList.size(); |
| | | if (successCount == 0) { |
| | | return "读åå¤±è´¥ï¼æªè§£æå°æ°æ®"; |
| | | } else { |
| | | if (errorCount == 0) { |
| | | return StrUtil.format("æåæ¨ï¼å
¨é¨è¯»åæåï¼å
±{}æ¡", successCount); |
| | | } else { |
| | | return ""; |
| | | } |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.core; |
| | | |
| | | import com.alibaba.excel.read.listener.ReadListener; |
| | | |
| | | /** |
| | | * Excel 导å
¥çå¬ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface ExcelListener<T> extends ReadListener<T> { |
| | | |
| | | ExcelResult<T> getExcelResult(); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.core; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * excelè¿å对象 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface ExcelResult<T> { |
| | | |
| | | /** |
| | | * 对象å表 |
| | | */ |
| | | List<T> getList(); |
| | | |
| | | /** |
| | | * é误å表 |
| | | */ |
| | | List<String> getErrorList(); |
| | | |
| | | /** |
| | | * 导å
¥åæ§ |
| | | */ |
| | | String getAnalysis(); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.excel.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.io.resource.ClassPathResource; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import com.alibaba.excel.EasyExcel; |
| | | import com.alibaba.excel.ExcelWriter; |
| | | import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; |
| | | import com.alibaba.excel.write.metadata.WriteSheet; |
| | | import com.alibaba.excel.write.metadata.fill.FillConfig; |
| | | import com.alibaba.excel.write.metadata.fill.FillWrapper; |
| | | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.core.utils.file.FileUtils; |
| | | import org.dromara.common.excel.convert.ExcelBigNumberConvert; |
| | | import org.dromara.common.excel.core.CellMergeStrategy; |
| | | import org.dromara.common.excel.core.DefaultExcelListener; |
| | | import org.dromara.common.excel.core.ExcelListener; |
| | | import org.dromara.common.excel.core.ExcelResult; |
| | | import jakarta.servlet.ServletOutputStream; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Excelç¸å
³å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class ExcelUtil { |
| | | |
| | | /** |
| | | * 忥坼å
¥(éç¨äºå°æ°æ®é) |
| | | * |
| | | * @param is è¾å
¥æµ |
| | | * @return 转æ¢åéå |
| | | */ |
| | | public static <T> List<T> importExcel(InputStream is, Class<T> clazz) { |
| | | return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * ä½¿ç¨æ ¡éªçå¬å¨ 弿¥å¯¼å
¥ 忥è¿å |
| | | * |
| | | * @param is è¾å
¥æµ |
| | | * @param clazz 对象类å |
| | | * @param isValidate æ¯å¦ Validator æ£éª é»è®¤ä¸ºæ¯ |
| | | * @return 转æ¢åéå |
| | | */ |
| | | public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) { |
| | | DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate); |
| | | EasyExcel.read(is, clazz, listener).sheet().doRead(); |
| | | return listener.getExcelResult(); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨èªå®ä¹çå¬å¨ 弿¥å¯¼å
¥ èªå®ä¹è¿å |
| | | * |
| | | * @param is è¾å
¥æµ |
| | | * @param clazz 对象类å |
| | | * @param listener èªå®ä¹çå¬å¨ |
| | | * @return 转æ¢åéå |
| | | */ |
| | | public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) { |
| | | EasyExcel.read(is, clazz, listener).sheet().doRead(); |
| | | return listener.getExcelResult(); |
| | | } |
| | | |
| | | /** |
| | | * 导åºexcel |
| | | * |
| | | * @param list å¯¼åºæ°æ®éå |
| | | * @param sheetName å·¥ä½è¡¨çåç§° |
| | | * @param clazz å®ä½ç±» |
| | | * @param response ååºä½ |
| | | */ |
| | | public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) { |
| | | try { |
| | | resetResponse(sheetName, response); |
| | | ServletOutputStream os = response.getOutputStream(); |
| | | exportExcel(list, sheetName, clazz, false, os); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("导åºExcelå¼å¸¸"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 导åºexcel |
| | | * |
| | | * @param list å¯¼åºæ°æ®éå |
| | | * @param sheetName å·¥ä½è¡¨çåç§° |
| | | * @param clazz å®ä½ç±» |
| | | * @param merge æ¯å¦åå¹¶åå
æ ¼ |
| | | * @param response ååºä½ |
| | | */ |
| | | public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response) { |
| | | try { |
| | | resetResponse(sheetName, response); |
| | | ServletOutputStream os = response.getOutputStream(); |
| | | exportExcel(list, sheetName, clazz, merge, os); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("导åºExcelå¼å¸¸"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 导åºexcel |
| | | * |
| | | * @param list å¯¼åºæ°æ®éå |
| | | * @param sheetName å·¥ä½è¡¨çåç§° |
| | | * @param clazz å®ä½ç±» |
| | | * @param os è¾åºæµ |
| | | */ |
| | | public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, OutputStream os) { |
| | | exportExcel(list, sheetName, clazz, false, os); |
| | | } |
| | | |
| | | /** |
| | | * 导åºexcel |
| | | * |
| | | * @param list å¯¼åºæ°æ®éå |
| | | * @param sheetName å·¥ä½è¡¨çåç§° |
| | | * @param clazz å®ä½ç±» |
| | | * @param merge æ¯å¦åå¹¶åå
æ ¼ |
| | | * @param os è¾åºæµ |
| | | */ |
| | | public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, OutputStream os) { |
| | | ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) |
| | | .autoCloseStream(false) |
| | | // èªå¨éé
|
| | | .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) |
| | | // 大æ°å¼èªå¨è½¬æ¢ 鲿¢å¤±ç |
| | | .registerConverter(new ExcelBigNumberConvert()) |
| | | .sheet(sheetName); |
| | | if (merge) { |
| | | // åå¹¶å¤çå¨ |
| | | builder.registerWriteHandler(new CellMergeStrategy(list, true)); |
| | | } |
| | | builder.doWrite(list); |
| | | } |
| | | |
| | | /** |
| | | * åè¡¨å¤æ°æ®æ¨¡æ¿å¯¼åº æ¨¡æ¿æ ¼å¼ä¸º {.屿§} |
| | | * |
| | | * @param filename æä»¶å |
| | | * @param templatePath 模æ¿è·¯å¾ resource ç®å½ä¸çè·¯å¾å
æ¬æ¨¡æ¿æä»¶å |
| | | * ä¾å¦: excel/temp.xlsx |
| | | * éç¹: æ¨¡æ¿æä»¶å¿
é¡»æ¾ç½®å°å¯å¨ç±»å¯¹åºç resource ç®å½ä¸ |
| | | * @param data 模æ¿éè¦çæ°æ® |
| | | * @param response ååºä½ |
| | | */ |
| | | public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) { |
| | | try { |
| | | resetResponse(filename, response); |
| | | ServletOutputStream os = response.getOutputStream(); |
| | | exportTemplate(data, templatePath, os); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("导åºExcelå¼å¸¸"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åè¡¨å¤æ°æ®æ¨¡æ¿å¯¼åº æ¨¡æ¿æ ¼å¼ä¸º {.屿§} |
| | | * |
| | | * @param templatePath 模æ¿è·¯å¾ resource ç®å½ä¸çè·¯å¾å
æ¬æ¨¡æ¿æä»¶å |
| | | * ä¾å¦: excel/temp.xlsx |
| | | * éç¹: æ¨¡æ¿æä»¶å¿
é¡»æ¾ç½®å°å¯å¨ç±»å¯¹åºç resource ç®å½ä¸ |
| | | * @param data 模æ¿éè¦çæ°æ® |
| | | * @param os è¾åºæµ |
| | | */ |
| | | public static void exportTemplate(List<Object> data, String templatePath, OutputStream os) { |
| | | ClassPathResource templateResource = new ClassPathResource(templatePath); |
| | | ExcelWriter excelWriter = EasyExcel.write(os) |
| | | .withTemplate(templateResource.getStream()) |
| | | .autoCloseStream(false) |
| | | // 大æ°å¼èªå¨è½¬æ¢ 鲿¢å¤±ç |
| | | .registerConverter(new ExcelBigNumberConvert()) |
| | | .build(); |
| | | WriteSheet writeSheet = EasyExcel.writerSheet().build(); |
| | | if (CollUtil.isEmpty(data)) { |
| | | throw new IllegalArgumentException("æ°æ®ä¸ºç©º"); |
| | | } |
| | | // åè¡¨å¤æ°æ®å¯¼åº æ¨¡æ¿æ ¼å¼ä¸º {.屿§} |
| | | for (Object d : data) { |
| | | excelWriter.fill(d, writeSheet); |
| | | } |
| | | excelWriter.finish(); |
| | | } |
| | | |
| | | /** |
| | | * å¤è¡¨å¤æ°æ®æ¨¡æ¿å¯¼åº æ¨¡æ¿æ ¼å¼ä¸º {key.屿§} |
| | | * |
| | | * @param filename æä»¶å |
| | | * @param templatePath 模æ¿è·¯å¾ resource ç®å½ä¸çè·¯å¾å
æ¬æ¨¡æ¿æä»¶å |
| | | * ä¾å¦: excel/temp.xlsx |
| | | * éç¹: æ¨¡æ¿æä»¶å¿
é¡»æ¾ç½®å°å¯å¨ç±»å¯¹åºç resource ç®å½ä¸ |
| | | * @param data 模æ¿éè¦çæ°æ® |
| | | * @param response ååºä½ |
| | | */ |
| | | public static void exportTemplateMultiList(Map<String, Object> data, String filename, String templatePath, HttpServletResponse response) { |
| | | try { |
| | | resetResponse(filename, response); |
| | | ServletOutputStream os = response.getOutputStream(); |
| | | exportTemplateMultiList(data, templatePath, os); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException("导åºExcelå¼å¸¸"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å¤è¡¨å¤æ°æ®æ¨¡æ¿å¯¼åº æ¨¡æ¿æ ¼å¼ä¸º {key.屿§} |
| | | * |
| | | * @param templatePath 模æ¿è·¯å¾ resource ç®å½ä¸çè·¯å¾å
æ¬æ¨¡æ¿æä»¶å |
| | | * ä¾å¦: excel/temp.xlsx |
| | | * éç¹: æ¨¡æ¿æä»¶å¿
é¡»æ¾ç½®å°å¯å¨ç±»å¯¹åºç resource ç®å½ä¸ |
| | | * @param data 模æ¿éè¦çæ°æ® |
| | | * @param os è¾åºæµ |
| | | */ |
| | | public static void exportTemplateMultiList(Map<String, Object> data, String templatePath, OutputStream os) { |
| | | ClassPathResource templateResource = new ClassPathResource(templatePath); |
| | | ExcelWriter excelWriter = EasyExcel.write(os) |
| | | .withTemplate(templateResource.getStream()) |
| | | .autoCloseStream(false) |
| | | // 大æ°å¼èªå¨è½¬æ¢ 鲿¢å¤±ç |
| | | .registerConverter(new ExcelBigNumberConvert()) |
| | | .build(); |
| | | WriteSheet writeSheet = EasyExcel.writerSheet().build(); |
| | | if (CollUtil.isEmpty(data)) { |
| | | throw new IllegalArgumentException("æ°æ®ä¸ºç©º"); |
| | | } |
| | | for (Map.Entry<String, Object> map : data.entrySet()) { |
| | | // 设置å表åç»è¿ææ°æ® |
| | | FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); |
| | | if (map.getValue() instanceof Collection) { |
| | | // å¤è¡¨å¯¼åºå¿
é¡»ä½¿ç¨ FillWrapper |
| | | excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet); |
| | | } else { |
| | | excelWriter.fill(map.getValue(), writeSheet); |
| | | } |
| | | } |
| | | excelWriter.finish(); |
| | | } |
| | | |
| | | /** |
| | | * éç½®ååºä½ |
| | | */ |
| | | private static void resetResponse(String sheetName, HttpServletResponse response) { |
| | | String filename = encodingFilename(sheetName); |
| | | FileUtils.setAttachmentResponseHeader(response, filename); |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); |
| | | } |
| | | |
| | | /** |
| | | * è§£æå¯¼åºå¼ 0=ç·,1=女,2=æªç¥ |
| | | * |
| | | * @param propertyValue åæ°å¼ |
| | | * @param converterExp ç¿»è¯æ³¨è§£ |
| | | * @param separator åé符 |
| | | * @return è§£æåå¼ |
| | | */ |
| | | public static String convertByExp(String propertyValue, String converterExp, String separator) { |
| | | StringBuilder propertyString = new StringBuilder(); |
| | | String[] convertSource = converterExp.split(StringUtils.SEPARATOR); |
| | | for (String item : convertSource) { |
| | | String[] itemArray = item.split("="); |
| | | if (StringUtils.containsAny(propertyValue, separator)) { |
| | | for (String value : propertyValue.split(separator)) { |
| | | if (itemArray[0].equals(value)) { |
| | | propertyString.append(itemArray[1]).append(separator); |
| | | break; |
| | | } |
| | | } |
| | | } else { |
| | | if (itemArray[0].equals(propertyValue)) { |
| | | return itemArray[1]; |
| | | } |
| | | } |
| | | } |
| | | return StringUtils.stripEnd(propertyString.toString(), separator); |
| | | } |
| | | |
| | | /** |
| | | * ååè§£æå¼ ç·=0,女=1,æªç¥=2 |
| | | * |
| | | * @param propertyValue åæ°å¼ |
| | | * @param converterExp ç¿»è¯æ³¨è§£ |
| | | * @param separator åé符 |
| | | * @return è§£æåå¼ |
| | | */ |
| | | public static String reverseByExp(String propertyValue, String converterExp, String separator) { |
| | | StringBuilder propertyString = new StringBuilder(); |
| | | String[] convertSource = converterExp.split(StringUtils.SEPARATOR); |
| | | for (String item : convertSource) { |
| | | String[] itemArray = item.split("="); |
| | | if (StringUtils.containsAny(propertyValue, separator)) { |
| | | for (String value : propertyValue.split(separator)) { |
| | | if (itemArray[1].equals(value)) { |
| | | propertyString.append(itemArray[0]).append(separator); |
| | | break; |
| | | } |
| | | } |
| | | } else { |
| | | if (itemArray[1].equals(propertyValue)) { |
| | | return itemArray[0]; |
| | | } |
| | | } |
| | | } |
| | | return StringUtils.stripEnd(propertyString.toString(), separator); |
| | | } |
| | | |
| | | /** |
| | | * ç¼ç æä»¶å |
| | | */ |
| | | public static String encodingFilename(String filename) { |
| | | return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; |
| | | } |
| | | |
| | | } |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.idempotent.annotation; |
| | | |
| | | import java.lang.annotation.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * èªå®ä¹æ³¨è§£é²æ¢è¡¨åéå¤æäº¤ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Inherited |
| | | @Target(ElementType.METHOD) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Documented |
| | | public @interface RepeatSubmit { |
| | | |
| | | /** |
| | | * é´éæ¶é´(ms)ï¼å°äºæ¤æ¶é´è§ä¸ºéå¤æäº¤ |
| | | */ |
| | | int interval() default 5000; |
| | | |
| | | TimeUnit timeUnit() default TimeUnit.MILLISECONDS; |
| | | |
| | | /** |
| | | * æç¤ºæ¶æ¯ æ¯æå½é
å æ ¼å¼ä¸º {code} |
| | | */ |
| | | String message() default "{repeat.submit.message}"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.idempotent.aspectj; |
| | | |
| | | import cn.dev33.satoken.SaManager; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.crypto.SecureUtil; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.MessageUtils; |
| | | import org.dromara.common.core.utils.ServletUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.idempotent.annotation.RepeatSubmit; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import org.aspectj.lang.JoinPoint; |
| | | import org.aspectj.lang.annotation.AfterReturning; |
| | | import org.aspectj.lang.annotation.AfterThrowing; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Before; |
| | | import org.springframework.validation.BindingResult; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.Collection; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 鲿¢éå¤æäº¤(åèç¾å¢GTISé²éç³»ç») |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Aspect |
| | | public class RepeatSubmitAspect { |
| | | |
| | | private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>(); |
| | | |
| | | @Before("@annotation(repeatSubmit)") |
| | | public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { |
| | | // å¦ææ³¨è§£ä¸ä¸º0 åä½¿ç¨æ³¨è§£æ°å¼ |
| | | long interval = 0; |
| | | if (repeatSubmit.interval() > 0) { |
| | | interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); |
| | | } |
| | | if (interval < 1000) { |
| | | throw new ServiceException("éå¤æäº¤é´éæ¶é´ä¸è½å°äº'1'ç§"); |
| | | } |
| | | HttpServletRequest request = ServletUtils.getRequest(); |
| | | String nowParams = argsArrayToString(point.getArgs()); |
| | | |
| | | // 请æ±å°åï¼ä½ä¸ºåæ¾cacheçkeyå¼ï¼ |
| | | String url = request.getRequestURI(); |
| | | |
| | | // å¯ä¸å¼ï¼æ²¡ææ¶æ¯å¤´å使ç¨è¯·æ±å°åï¼ |
| | | String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName())); |
| | | |
| | | submitKey = SecureUtil.md5(submitKey + ":" + nowParams); |
| | | // å¯ä¸æ è¯ï¼æå®key + url + æ¶æ¯å¤´ï¼ |
| | | String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; |
| | | String key = RedisUtils.getCacheObject(cacheRepeatKey); |
| | | if (key == null) { |
| | | RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval)); |
| | | KEY_CACHE.set(cacheRepeatKey); |
| | | } else { |
| | | String message = repeatSubmit.message(); |
| | | if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { |
| | | message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); |
| | | } |
| | | throw new ServiceException(message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å¤çå®è¯·æ±åæ§è¡ |
| | | * |
| | | * @param joinPoint åç¹ |
| | | */ |
| | | @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult") |
| | | public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) { |
| | | if (jsonResult instanceof R r) { |
| | | try { |
| | | // æååä¸å é¤redisæ°æ® ä¿è¯å¨æææ¶é´å
æ æ³éå¤æäº¤ |
| | | if (r.getCode() == R.SUCCESS) { |
| | | return; |
| | | } |
| | | RedisUtils.deleteObject(KEY_CACHE.get()); |
| | | } finally { |
| | | KEY_CACHE.remove(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¦æªå¼å¸¸æä½ |
| | | * |
| | | * @param joinPoint åç¹ |
| | | * @param e å¼å¸¸ |
| | | */ |
| | | @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") |
| | | public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { |
| | | RedisUtils.deleteObject(KEY_CACHE.get()); |
| | | KEY_CACHE.remove(); |
| | | } |
| | | |
| | | /** |
| | | * åæ°æ¼è£
|
| | | */ |
| | | private String argsArrayToString(Object[] paramsArray) { |
| | | StringBuilder params = new StringBuilder(); |
| | | if (paramsArray != null && paramsArray.length > 0) { |
| | | for (Object o : paramsArray) { |
| | | if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { |
| | | try { |
| | | params.append(JsonUtils.toJsonString(o)).append(" "); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return params.toString().trim(); |
| | | } |
| | | |
| | | /** |
| | | * 夿æ¯å¦éè¦è¿æ»¤ç对象ã |
| | | * |
| | | * @param o 对象信æ¯ã |
| | | * @return 妿æ¯éè¦è¿æ»¤ç对象ï¼åè¿åtrueï¼å¦åè¿åfalseã |
| | | */ |
| | | @SuppressWarnings("rawtypes") |
| | | public boolean isFilterObject(final Object o) { |
| | | Class<?> clazz = o.getClass(); |
| | | if (clazz.isArray()) { |
| | | return clazz.getComponentType().isAssignableFrom(MultipartFile.class); |
| | | } else if (Collection.class.isAssignableFrom(clazz)) { |
| | | Collection collection = (Collection) o; |
| | | for (Object value : collection) { |
| | | return value instanceof MultipartFile; |
| | | } |
| | | } else if (Map.class.isAssignableFrom(clazz)) { |
| | | Map map = (Map) o; |
| | | for (Object value : map.entrySet()) { |
| | | Map.Entry entry = (Map.Entry) value; |
| | | return entry.getValue() instanceof MultipartFile; |
| | | } |
| | | } |
| | | return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse |
| | | || o instanceof BindingResult; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.idempotent.config; |
| | | |
| | | import org.dromara.common.idempotent.aspectj.RepeatSubmitAspect; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.data.redis.connection.RedisConfiguration; |
| | | |
| | | /** |
| | | * å¹çåè½é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration(after = RedisConfiguration.class) |
| | | public class IdempotentConfig { |
| | | |
| | | @Bean |
| | | public RepeatSubmitAspect repeatSubmitAspect() { |
| | | return new RepeatSubmitAspect(); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.idempotent.config.IdempotentConfig |
| | | org.dromara.common.idempotent.config.IdempotentConfig |
| | |
| | | xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.job.config; |
| | | |
| | | import org.dromara.common.job.config.properties.XxlJobProperties; |
| | | import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | /** |
| | | * xxl-job config |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(XxlJobProperties.class) |
| | | @ConditionalOnProperty(prefix = "xxl.job", name = "enabled", havingValue = "true") |
| | | public class XxlJobConfig { |
| | | |
| | | @Bean |
| | | public XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties xxlJobProperties) { |
| | | log.info(">>>>>>>>>>> xxl-job config init."); |
| | | XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); |
| | | xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdminAddresses()); |
| | | xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken()); |
| | | XxlJobProperties.Executor executor = xxlJobProperties.getExecutor(); |
| | | xxlJobSpringExecutor.setAppname(executor.getAppname()); |
| | | xxlJobSpringExecutor.setAddress(executor.getAddress()); |
| | | xxlJobSpringExecutor.setIp(executor.getIp()); |
| | | xxlJobSpringExecutor.setPort(executor.getPort()); |
| | | xxlJobSpringExecutor.setLogPath(executor.getLogPath()); |
| | | xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays()); |
| | | return xxlJobSpringExecutor; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.job.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * xxljobé
置类 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "xxl.job") |
| | | public class XxlJobProperties { |
| | | |
| | | private Boolean enabled; |
| | | |
| | | private String adminAddresses; |
| | | |
| | | private String accessToken; |
| | | |
| | | private Executor executor; |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public static class Executor { |
| | | |
| | | private String appname; |
| | | |
| | | private String address; |
| | | |
| | | private String ip; |
| | | |
| | | private int port; |
| | | |
| | | private String logPath; |
| | | |
| | | private int logRetentionDays; |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.job.config.XxlJobConfig |
| | | org.dromara.common.job.config.XxlJobConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.json.config; |
| | | |
| | | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; |
| | | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| | | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; |
| | | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; |
| | | import org.dromara.common.json.handler.BigNumberSerializer; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; |
| | | import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.BigInteger; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.TimeZone; |
| | | |
| | | /** |
| | | * jackson é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @AutoConfiguration(before = JacksonAutoConfiguration.class) |
| | | public class JacksonConfig { |
| | | |
| | | @Bean |
| | | public Jackson2ObjectMapperBuilderCustomizer customizer() { |
| | | return builder -> { |
| | | // å
¨å±é
ç½®åºååè¿å JSON å¤ç |
| | | JavaTimeModule javaTimeModule = new JavaTimeModule(); |
| | | javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); |
| | | javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); |
| | | javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); |
| | | javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); |
| | | javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); |
| | | builder.modules(javaTimeModule); |
| | | builder.timeZone(TimeZone.getDefault()); |
| | | log.info("åå§å jackson é
ç½®"); |
| | | }; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.json.handler; |
| | | |
| | | import com.fasterxml.jackson.core.JsonGenerator; |
| | | import com.fasterxml.jackson.databind.SerializerProvider; |
| | | import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; |
| | | import com.fasterxml.jackson.databind.ser.std.NumberSerializer; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * è¶
åº JS æå¤§æå°å¼ å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @JacksonStdImpl |
| | | public class BigNumberSerializer extends NumberSerializer { |
| | | |
| | | /** |
| | | * æ ¹æ® JS Number.MAX_SAFE_INTEGER ä¸ Number.MIN_SAFE_INTEGER 徿¥ |
| | | */ |
| | | private static final long MAX_SAFE_INTEGER = 9007199254740991L; |
| | | private static final long MIN_SAFE_INTEGER = -9007199254740991L; |
| | | |
| | | /** |
| | | * æä¾å®ä¾ |
| | | */ |
| | | public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); |
| | | |
| | | public BigNumberSerializer(Class<? extends Number> rawType) { |
| | | super(rawType); |
| | | } |
| | | |
| | | @Override |
| | | public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { |
| | | // è¶
åºèå´ åºååä½å符串 |
| | | if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { |
| | | super.serialize(value, gen, provider); |
| | | } else { |
| | | gen.writeString(value.toString()); |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.json.utils; |
| | | |
| | | import cn.hutool.core.lang.Dict; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.exc.MismatchedInputException; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * JSON å·¥å
·ç±» |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class JsonUtils { |
| | | |
| | | private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); |
| | | |
| | | public static ObjectMapper getObjectMapper() { |
| | | return OBJECT_MAPPER; |
| | | } |
| | | |
| | | public static String toJsonString(Object object) { |
| | | if (ObjectUtil.isNull(object)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.writeValueAsString(object); |
| | | } catch (JsonProcessingException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static <T> T parseObject(String text, Class<T> clazz) { |
| | | if (StringUtils.isEmpty(text)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(text, clazz); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static <T> T parseObject(byte[] bytes, Class<T> clazz) { |
| | | if (ArrayUtil.isEmpty(bytes)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(bytes, clazz); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static <T> T parseObject(String text, TypeReference<T> typeReference) { |
| | | if (StringUtils.isBlank(text)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(text, typeReference); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static Dict parseMap(String text) { |
| | | if (StringUtils.isBlank(text)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); |
| | | } catch (MismatchedInputException e) { |
| | | // ç±»åä¸å¹é
说æä¸æ¯json |
| | | return null; |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static List<Dict> parseArrayMap(String text) { |
| | | if (StringUtils.isBlank(text)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | public static <T> List<T> parseArray(String text, Class<T> clazz) { |
| | | if (StringUtils.isEmpty(text)) { |
| | | return new ArrayList<>(); |
| | | } |
| | | try { |
| | | return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.json.config.JacksonConfig |
| | | org.dromara.common.json.config.JacksonConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | <dependencies> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-satoken</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.annotation; |
| | | |
| | | import org.dromara.common.log.enums.BusinessType; |
| | | import org.dromara.common.log.enums.OperatorType; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * èªå®ä¹æä½æ¥å¿è®°å½æ³¨è§£ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Target({ElementType.PARAMETER, ElementType.METHOD}) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Documented |
| | | public @interface Log { |
| | | /** |
| | | * 模å |
| | | */ |
| | | String title() default ""; |
| | | |
| | | /** |
| | | * åè½ |
| | | */ |
| | | BusinessType businessType() default BusinessType.OTHER; |
| | | |
| | | /** |
| | | * æä½äººç±»å« |
| | | */ |
| | | OperatorType operatorType() default OperatorType.MANAGE; |
| | | |
| | | /** |
| | | * æ¯å¦ä¿å请æ±çåæ° |
| | | */ |
| | | boolean isSaveRequestData() default true; |
| | | |
| | | /** |
| | | * æ¯å¦ä¿åååºçåæ° |
| | | */ |
| | | boolean isSaveResponseData() default true; |
| | | |
| | | |
| | | /** |
| | | * æé¤æå®ç请æ±åæ° |
| | | */ |
| | | String[] excludeParamNames() default {}; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.aspect; |
| | | |
| | | import cn.hutool.core.lang.Dict; |
| | | import cn.hutool.core.map.MapUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.alibaba.ttl.TransmittableThreadLocal; |
| | | import org.dromara.common.core.utils.ServletUtils; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.log.annotation.Log; |
| | | import org.dromara.common.log.enums.BusinessStatus; |
| | | import org.dromara.common.log.event.OperLogEvent; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.time.StopWatch; |
| | | import org.aspectj.lang.JoinPoint; |
| | | import org.aspectj.lang.annotation.AfterReturning; |
| | | import org.aspectj.lang.annotation.AfterThrowing; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Before; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.http.HttpMethod; |
| | | import org.springframework.validation.BindingResult; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æä½æ¥å¿è®°å½å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @Aspect |
| | | @AutoConfiguration |
| | | public class LogAspect { |
| | | |
| | | /** |
| | | * æé¤ææå±æ§å段 |
| | | */ |
| | | public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; |
| | | |
| | | |
| | | /** |
| | | * è®¡ç®æä½æ¶èæ¶é´ |
| | | */ |
| | | private static final ThreadLocal<StopWatch> TIME_THREADLOCAL = new TransmittableThreadLocal<>(); |
| | | |
| | | /** |
| | | * å¤ç请æ±åæ§è¡ |
| | | */ |
| | | @Before(value = "@annotation(controllerLog)") |
| | | public void boBefore(JoinPoint joinPoint, Log controllerLog) { |
| | | StopWatch stopWatch = new StopWatch(); |
| | | TIME_THREADLOCAL.set(stopWatch); |
| | | stopWatch.start(); |
| | | } |
| | | |
| | | /** |
| | | * å¤çå®è¯·æ±åæ§è¡ |
| | | * |
| | | * @param joinPoint åç¹ |
| | | */ |
| | | @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") |
| | | public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { |
| | | handleLog(joinPoint, controllerLog, null, jsonResult); |
| | | } |
| | | |
| | | /** |
| | | * æ¦æªå¼å¸¸æä½ |
| | | * |
| | | * @param joinPoint åç¹ |
| | | * @param e å¼å¸¸ |
| | | */ |
| | | @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") |
| | | public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { |
| | | handleLog(joinPoint, controllerLog, e, null); |
| | | } |
| | | |
| | | protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { |
| | | try { |
| | | |
| | | // *========æ°æ®åºæ¥å¿=========*// |
| | | OperLogEvent operLog = new OperLogEvent(); |
| | | operLog.setTenantId(LoginHelper.getTenantId()); |
| | | operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); |
| | | // 请æ±çå°å |
| | | String ip = ServletUtils.getClientIP(); |
| | | operLog.setOperIp(ip); |
| | | operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); |
| | | operLog.setOperName(LoginHelper.getUsername()); |
| | | |
| | | if (e != null) { |
| | | operLog.setStatus(BusinessStatus.FAIL.ordinal()); |
| | | operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); |
| | | } |
| | | // è®¾ç½®æ¹æ³åç§° |
| | | String className = joinPoint.getTarget().getClass().getName(); |
| | | String methodName = joinPoint.getSignature().getName(); |
| | | operLog.setMethod(className + "." + methodName + "()"); |
| | | // è®¾ç½®è¯·æ±æ¹å¼ |
| | | operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); |
| | | // å¤ç设置注解ä¸çåæ° |
| | | getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); |
| | | // 设置æ¶èæ¶é´ |
| | | StopWatch stopWatch = TIME_THREADLOCAL.get(); |
| | | stopWatch.stop(); |
| | | operLog.setCostTime(stopWatch.getTime()); |
| | | // åå¸äºä»¶ä¿åæ°æ®åº |
| | | SpringUtils.context().publishEvent(operLog); |
| | | } catch (Exception exp) { |
| | | // è®°å½æ¬å°å¼å¸¸æ¥å¿ |
| | | log.error("å¼å¸¸ä¿¡æ¯:{}", exp.getMessage()); |
| | | exp.printStackTrace(); |
| | | } finally { |
| | | TIME_THREADLOCAL.remove(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·å注解ä¸å¯¹æ¹æ³çæè¿°ä¿¡æ¯ ç¨äºController屿³¨è§£ |
| | | * |
| | | * @param log æ¥å¿ |
| | | * @param operLog æä½æ¥å¿ |
| | | * @throws Exception |
| | | */ |
| | | public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception { |
| | | // 设置actionå¨ä½ |
| | | operLog.setBusinessType(log.businessType().ordinal()); |
| | | // 设置æ é¢ |
| | | operLog.setTitle(log.title()); |
| | | // 设置æä½äººç±»å« |
| | | operLog.setOperatorType(log.operatorType().ordinal()); |
| | | // æ¯å¦éè¦ä¿årequestï¼åæ°åå¼ |
| | | if (log.isSaveRequestData()) { |
| | | // è·ååæ°çä¿¡æ¯ï¼ä¼ å
¥å°æ°æ®åºä¸ã |
| | | setRequestValue(joinPoint, operLog, log.excludeParamNames()); |
| | | } |
| | | // æ¯å¦éè¦ä¿åresponseï¼åæ°åå¼ |
| | | if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { |
| | | operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·å请æ±çåæ°ï¼æ¾å°logä¸ |
| | | * |
| | | * @param operLog æä½æ¥å¿ |
| | | * @throws Exception å¼å¸¸ |
| | | */ |
| | | private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { |
| | | Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); |
| | | String requestMethod = operLog.getRequestMethod(); |
| | | if (MapUtil.isEmpty(paramsMap) |
| | | && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { |
| | | String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); |
| | | operLog.setOperParam(StringUtils.substring(params, 0, 2000)); |
| | | } else { |
| | | MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); |
| | | MapUtil.removeAny(paramsMap, excludeParamNames); |
| | | operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åæ°æ¼è£
|
| | | */ |
| | | private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { |
| | | StringBuilder params = new StringBuilder(); |
| | | if (paramsArray != null && paramsArray.length > 0) { |
| | | for (Object o : paramsArray) { |
| | | if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { |
| | | try { |
| | | String str = JsonUtils.toJsonString(o); |
| | | Dict dict = JsonUtils.parseMap(str); |
| | | if (MapUtil.isNotEmpty(dict)) { |
| | | MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); |
| | | MapUtil.removeAny(dict, excludeParamNames); |
| | | str = JsonUtils.toJsonString(dict); |
| | | } |
| | | params.append(str).append(" "); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return params.toString().trim(); |
| | | } |
| | | |
| | | /** |
| | | * 夿æ¯å¦éè¦è¿æ»¤ç对象ã |
| | | * |
| | | * @param o 对象信æ¯ã |
| | | * @return 妿æ¯éè¦è¿æ»¤ç对象ï¼åè¿åtrueï¼å¦åè¿åfalseã |
| | | */ |
| | | @SuppressWarnings("rawtypes") |
| | | public boolean isFilterObject(final Object o) { |
| | | Class<?> clazz = o.getClass(); |
| | | if (clazz.isArray()) { |
| | | return clazz.getComponentType().isAssignableFrom(MultipartFile.class); |
| | | } else if (Collection.class.isAssignableFrom(clazz)) { |
| | | Collection collection = (Collection) o; |
| | | for (Object value : collection) { |
| | | return value instanceof MultipartFile; |
| | | } |
| | | } else if (Map.class.isAssignableFrom(clazz)) { |
| | | Map map = (Map) o; |
| | | for (Object value : map.entrySet()) { |
| | | Map.Entry entry = (Map.Entry) value; |
| | | return entry.getValue() instanceof MultipartFile; |
| | | } |
| | | } |
| | | return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse |
| | | || o instanceof BindingResult; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.enums; |
| | | |
| | | /** |
| | | * æä½ç¶æ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public enum BusinessStatus { |
| | | /** |
| | | * æå |
| | | */ |
| | | SUCCESS, |
| | | |
| | | /** |
| | | * 失败 |
| | | */ |
| | | FAIL, |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.enums; |
| | | |
| | | /** |
| | | * ä¸å¡æä½ç±»å |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public enum BusinessType { |
| | | /** |
| | | * å
¶å® |
| | | */ |
| | | OTHER, |
| | | |
| | | /** |
| | | * æ°å¢ |
| | | */ |
| | | INSERT, |
| | | |
| | | /** |
| | | * ä¿®æ¹ |
| | | */ |
| | | UPDATE, |
| | | |
| | | /** |
| | | * å é¤ |
| | | */ |
| | | DELETE, |
| | | |
| | | /** |
| | | * ææ |
| | | */ |
| | | GRANT, |
| | | |
| | | /** |
| | | * å¯¼åº |
| | | */ |
| | | EXPORT, |
| | | |
| | | /** |
| | | * 导å
¥ |
| | | */ |
| | | IMPORT, |
| | | |
| | | /** |
| | | * 强é |
| | | */ |
| | | FORCE, |
| | | |
| | | /** |
| | | * çæä»£ç |
| | | */ |
| | | GENCODE, |
| | | |
| | | /** |
| | | * æ¸
ç©ºæ°æ® |
| | | */ |
| | | CLEAN, |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.enums; |
| | | |
| | | /** |
| | | * æä½äººç±»å« |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public enum OperatorType { |
| | | /** |
| | | * å
¶å® |
| | | */ |
| | | OTHER, |
| | | |
| | | /** |
| | | * åå°ç¨æ· |
| | | */ |
| | | MANAGE, |
| | | |
| | | /** |
| | | * ææºç«¯ç¨æ· |
| | | */ |
| | | MOBILE |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.event; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * ç»å½äºä»¶ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class LogininforEvent implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * ç¨æ·è´¦å· |
| | | */ |
| | | private String username; |
| | | |
| | | /** |
| | | * ç»å½ç¶æ 0æå 1失败 |
| | | */ |
| | | private String status; |
| | | |
| | | /** |
| | | * æç¤ºæ¶æ¯ |
| | | */ |
| | | private String message; |
| | | |
| | | /** |
| | | * 请æ±ä½ |
| | | */ |
| | | private HttpServletRequest request; |
| | | |
| | | /** |
| | | * å
¶ä»åæ° |
| | | */ |
| | | private Object[] args; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.log.event; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * æä½æ¥å¿äºä»¶ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class OperLogEvent implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * æ¥å¿ä¸»é® |
| | | */ |
| | | private Long operId; |
| | | |
| | | /** |
| | | * ç§æ·ID |
| | | */ |
| | | private String tenantId; |
| | | |
| | | /** |
| | | * æä½æ¨¡å |
| | | */ |
| | | private String title; |
| | | |
| | | /** |
| | | * ä¸å¡ç±»åï¼0å
¶å® 1æ°å¢ 2ä¿®æ¹ 3å é¤ï¼ |
| | | */ |
| | | private Integer businessType; |
| | | |
| | | /** |
| | | * ä¸å¡ç±»åæ°ç» |
| | | */ |
| | | private Integer[] businessTypes; |
| | | |
| | | /** |
| | | * è¯·æ±æ¹æ³ |
| | | */ |
| | | private String method; |
| | | |
| | | /** |
| | | * è¯·æ±æ¹å¼ |
| | | */ |
| | | private String requestMethod; |
| | | |
| | | /** |
| | | * æä½ç±»å«ï¼0å
¶å® 1åå°ç¨æ· 2ææºç«¯ç¨æ·ï¼ |
| | | */ |
| | | private Integer operatorType; |
| | | |
| | | /** |
| | | * æä½äººå |
| | | */ |
| | | private String operName; |
| | | |
| | | /** |
| | | * é¨é¨åç§° |
| | | */ |
| | | private String deptName; |
| | | |
| | | /** |
| | | * 请æ±url |
| | | */ |
| | | private String operUrl; |
| | | |
| | | /** |
| | | * æä½å°å |
| | | */ |
| | | private String operIp; |
| | | |
| | | /** |
| | | * æä½å°ç¹ |
| | | */ |
| | | private String operLocation; |
| | | |
| | | /** |
| | | * 请æ±åæ° |
| | | */ |
| | | private String operParam; |
| | | |
| | | /** |
| | | * è¿ååæ° |
| | | */ |
| | | private String jsonResult; |
| | | |
| | | /** |
| | | * æä½ç¶æï¼0æ£å¸¸ 1å¼å¸¸ï¼ |
| | | */ |
| | | private Integer status; |
| | | |
| | | /** |
| | | * éè¯¯æ¶æ¯ |
| | | */ |
| | | private String errorMsg; |
| | | |
| | | /** |
| | | * æä½æ¶é´ |
| | | */ |
| | | private Date operTime; |
| | | |
| | | /** |
| | | * æ¶èæ¶é´ |
| | | */ |
| | | private Long costTime; |
| | | } |
| | |
| | | com.ruoyi.common.log.aspect.LogAspect |
| | | org.dromara.common.log.aspect.LogAspect |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.config; |
| | | |
| | | import cn.hutool.extra.mail.MailAccount; |
| | | import org.dromara.common.mail.config.properties.MailProperties; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | /** |
| | | * JavaMail é
ç½® |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(MailProperties.class) |
| | | public class MailConfig { |
| | | |
| | | @Bean |
| | | @ConditionalOnProperty(value = "mail.enabled", havingValue = "true") |
| | | public MailAccount mailAccount(MailProperties mailProperties) { |
| | | MailAccount account = new MailAccount(); |
| | | account.setHost(mailProperties.getHost()); |
| | | account.setPort(mailProperties.getPort()); |
| | | account.setAuth(mailProperties.getAuth()); |
| | | account.setFrom(mailProperties.getFrom()); |
| | | account.setUser(mailProperties.getUser()); |
| | | account.setPass(mailProperties.getPass()); |
| | | account.setSocketFactoryPort(mailProperties.getPort()); |
| | | account.setStarttlsEnable(mailProperties.getStarttlsEnable()); |
| | | account.setSslEnable(mailProperties.getSslEnable()); |
| | | account.setTimeout(mailProperties.getTimeout()); |
| | | account.setConnectionTimeout(mailProperties.getConnectionTimeout()); |
| | | return account; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * JavaMail é
ç½®å±æ§ |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "mail") |
| | | public class MailProperties { |
| | | |
| | | /** |
| | | * è¿æ»¤å¼å
³ |
| | | */ |
| | | private Boolean enabled; |
| | | |
| | | /** |
| | | * SMTPæå¡å¨åå |
| | | */ |
| | | private String host; |
| | | |
| | | /** |
| | | * SMTPæå¡ç«¯å£ |
| | | */ |
| | | private Integer port; |
| | | |
| | | /** |
| | | * æ¯å¦éè¦ç¨æ·åå¯ç éªè¯ |
| | | */ |
| | | private Boolean auth; |
| | | |
| | | /** |
| | | * ç¨æ·å |
| | | */ |
| | | private String user; |
| | | |
| | | /** |
| | | * å¯ç |
| | | */ |
| | | private String pass; |
| | | |
| | | /** |
| | | * åéæ¹ï¼éµå¾ªRFC-822æ å |
| | | */ |
| | | private String from; |
| | | |
| | | /** |
| | | * ä½¿ç¨ STARTTLSå®å
¨è¿æ¥ï¼STARTTLSæ¯å¯¹çº¯ææ¬éä¿¡åè®®çæ©å±ãå®å°çº¯ææ¬è¿æ¥å级为å å¯è¿æ¥ï¼TLSæSSLï¼ï¼ è䏿¯ä½¿ç¨ä¸ä¸ªåç¬çå å¯é信端å£ã |
| | | */ |
| | | private Boolean starttlsEnable; |
| | | |
| | | /** |
| | | * ä½¿ç¨ SSLå®å
¨è¿æ¥ |
| | | */ |
| | | private Boolean sslEnable; |
| | | |
| | | /** |
| | | * SMTPè¶
æ¶æ¶é¿ï¼å使¯«ç§ï¼ç¼ºçå¼ä¸è¶
æ¶ |
| | | */ |
| | | private Long timeout; |
| | | |
| | | /** |
| | | * Socketè¿æ¥è¶
æ¶å¼ï¼å使¯«ç§ï¼ç¼ºçå¼ä¸è¶
æ¶ |
| | | */ |
| | | private Long connectionTimeout; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.utils; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.extra.mail.MailException; |
| | | import jakarta.mail.internet.AddressException; |
| | | import jakarta.mail.internet.InternetAddress; |
| | | import jakarta.mail.internet.MimeUtility; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.nio.charset.Charset; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * é®ä»¶å
é¨å·¥å
·ç±» |
| | | * @author looly |
| | | * @since 3.2.3 |
| | | */ |
| | | public class InternalMailUtil { |
| | | |
| | | /** |
| | | * å°å¤ä¸ªå符串é®ä»¶å°å转为{@link InternetAddress}å表<br> |
| | | * å个å符串å°åå¯ä»¥æ¯å¤ä¸ªå°ååå¹¶çå符串 |
| | | * |
| | | * @param addrStrs å°åæ°ç» |
| | | * @param charset ç¼ç ï¼ä¸»è¦ç¨äºä¸æç¨æ·åçç¼ç ï¼ |
| | | * @return å°åæ°ç» |
| | | * @since 4.0.3 |
| | | */ |
| | | public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) { |
| | | final List<InternetAddress> resultList = new ArrayList<>(addrStrs.length); |
| | | InternetAddress[] addrs; |
| | | for (String addrStr : addrStrs) { |
| | | addrs = parseAddress(addrStr, charset); |
| | | if (ArrayUtil.isNotEmpty(addrs)) { |
| | | Collections.addAll(resultList, addrs); |
| | | } |
| | | } |
| | | return resultList.toArray(new InternetAddress[0]); |
| | | } |
| | | |
| | | /** |
| | | * è§£æç¬¬ä¸ä¸ªå°å |
| | | * |
| | | * @param address å°åå符串 |
| | | * @param charset ç¼ç ï¼{@code null}表示使ç¨ç³»ç»å±æ§å®ä¹çç¼ç æç³»ç»ç¼ç |
| | | * @return å°åå表 |
| | | */ |
| | | public static InternetAddress parseFirstAddress(String address, Charset charset) { |
| | | final InternetAddress[] internetAddresses = parseAddress(address, charset); |
| | | if (ArrayUtil.isEmpty(internetAddresses)) { |
| | | try { |
| | | return new InternetAddress(address); |
| | | } catch (AddressException e) { |
| | | throw new MailException(e); |
| | | } |
| | | } |
| | | return internetAddresses[0]; |
| | | } |
| | | |
| | | /** |
| | | * å°ä¸ä¸ªå°åå符串解æä¸ºå¤ä¸ªå°å<br> |
| | | * å°åé´ä½¿ç¨" "ã","ã";"åé |
| | | * |
| | | * @param address å°åå符串 |
| | | * @param charset ç¼ç ï¼{@code null}表示使ç¨ç³»ç»å±æ§å®ä¹çç¼ç æç³»ç»ç¼ç |
| | | * @return å°åå表 |
| | | */ |
| | | public static InternetAddress[] parseAddress(String address, Charset charset) { |
| | | InternetAddress[] addresses; |
| | | try { |
| | | addresses = InternetAddress.parse(address); |
| | | } catch (AddressException e) { |
| | | throw new MailException(e); |
| | | } |
| | | //ç¼ç ç¨æ·å |
| | | if (ArrayUtil.isNotEmpty(addresses)) { |
| | | final String charsetStr = null == charset ? null : charset.name(); |
| | | for (InternetAddress internetAddress : addresses) { |
| | | try { |
| | | internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new MailException(e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return addresses; |
| | | } |
| | | |
| | | /** |
| | | * ç¼ç 䏿å符<br> |
| | | * ç¼ç 失败è¿ååå符串 |
| | | * |
| | | * @param text 被ç¼ç çææ¬ |
| | | * @param charset ç¼ç |
| | | * @return ç¼ç åçç»æ |
| | | */ |
| | | public static String encodeText(String text, Charset charset) { |
| | | try { |
| | | return MimeUtility.encodeText(text, charset.name(), null); |
| | | } catch (UnsupportedEncodingException e) { |
| | | // ignore |
| | | } |
| | | return text; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.utils; |
| | | |
| | | import cn.hutool.core.builder.Builder; |
| | | import cn.hutool.core.io.FileUtil; |
| | | import cn.hutool.core.io.IORuntimeException; |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.extra.mail.*; |
| | | import jakarta.activation.DataHandler; |
| | | import jakarta.activation.DataSource; |
| | | import jakarta.activation.FileDataSource; |
| | | import jakarta.activation.FileTypeMap; |
| | | import jakarta.mail.*; |
| | | import jakarta.mail.internet.MimeBodyPart; |
| | | import jakarta.mail.internet.MimeMessage; |
| | | import jakarta.mail.internet.MimeMultipart; |
| | | import jakarta.mail.internet.MimeUtility; |
| | | import jakarta.mail.util.ByteArrayDataSource; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.PrintStream; |
| | | import java.nio.charset.Charset; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * é®ä»¶åé客æ·ç«¯ |
| | | * |
| | | * @author looly |
| | | * @since 3.2.0 |
| | | */ |
| | | public class Mail implements Builder<MimeMessage> { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * é®ç®±å¸æ·ä¿¡æ¯ä»¥åä¸äºå®¢æ·ç«¯é
ç½®ä¿¡æ¯ |
| | | */ |
| | | private final MailAccount mailAccount; |
| | | /** |
| | | * æ¶ä»¶äººå表 |
| | | */ |
| | | private String[] tos; |
| | | /** |
| | | * æé人å表ï¼carbon copyï¼ |
| | | */ |
| | | private String[] ccs; |
| | | /** |
| | | * å¯é人å表ï¼blind carbon copyï¼ |
| | | */ |
| | | private String[] bccs; |
| | | /** |
| | | * åå¤å°å(reply-to) |
| | | */ |
| | | private String[] reply; |
| | | /** |
| | | * æ é¢ |
| | | */ |
| | | private String title; |
| | | /** |
| | | * å
容 |
| | | */ |
| | | private String content; |
| | | /** |
| | | * æ¯å¦ä¸ºHTML |
| | | */ |
| | | private boolean isHtml; |
| | | /** |
| | | * æ£æãéä»¶åå¾ççæ··åé¨å |
| | | */ |
| | | private final Multipart multipart = new MimeMultipart(); |
| | | /** |
| | | * æ¯å¦ä½¿ç¨å
¨å±ä¼è¯ï¼é»è®¤ä¸ºfalse |
| | | */ |
| | | private boolean useGlobalSession = false; |
| | | |
| | | /** |
| | | * debugè¾åºä½ç½®ï¼å¯ä»¥èªå®ä¹debugæ¥å¿ |
| | | */ |
| | | private PrintStream debugOutput; |
| | | |
| | | /** |
| | | * å建é®ä»¶å®¢æ·ç«¯ |
| | | * |
| | | * @param mailAccount é®ä»¶å¸å· |
| | | * @return Mail |
| | | */ |
| | | public static Mail create(MailAccount mailAccount) { |
| | | return new Mail(mailAccount); |
| | | } |
| | | |
| | | /** |
| | | * å建é®ä»¶å®¢æ·ç«¯ï¼ä½¿ç¨å
¨å±é®ä»¶å¸æ· |
| | | * |
| | | * @return Mail |
| | | */ |
| | | public static Mail create() { |
| | | return new Mail(); |
| | | } |
| | | |
| | | // --------------------------------------------------------------- Constructor start |
| | | |
| | | /** |
| | | * æé ï¼ä½¿ç¨å
¨å±é®ä»¶å¸æ· |
| | | */ |
| | | public Mail() { |
| | | this(GlobalMailAccount.INSTANCE.getAccount()); |
| | | } |
| | | |
| | | /** |
| | | * æé |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ï¼å¦æä¸ºnull使ç¨é»è®¤é
ç½®æä»¶çå
¨å±é®ä»¶é
ç½® |
| | | */ |
| | | public Mail(MailAccount mailAccount) { |
| | | mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount(); |
| | | this.mailAccount = mailAccount.defaultIfEmpty(); |
| | | } |
| | | // --------------------------------------------------------------- Constructor end |
| | | |
| | | // --------------------------------------------------------------- Getters and Setters start |
| | | |
| | | /** |
| | | * 设置æ¶ä»¶äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @return this |
| | | * @see #setTos(String...) |
| | | */ |
| | | public Mail to(String... tos) { |
| | | return setTos(tos); |
| | | } |
| | | |
| | | /** |
| | | * 设置å¤ä¸ªæ¶ä»¶äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @return this |
| | | */ |
| | | public Mail setTos(String... tos) { |
| | | this.tos = tos; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置å¤ä¸ªæé人ï¼carbon copyï¼ |
| | | * |
| | | * @param ccs æé人å表 |
| | | * @return this |
| | | * @since 4.0.3 |
| | | */ |
| | | public Mail setCcs(String... ccs) { |
| | | this.ccs = ccs; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置å¤ä¸ªå¯é人ï¼blind carbon copyï¼ |
| | | * |
| | | * @param bccs å¯é人å表 |
| | | * @return this |
| | | * @since 4.0.3 |
| | | */ |
| | | public Mail setBccs(String... bccs) { |
| | | this.bccs = bccs; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置å¤ä¸ªåå¤å°å(reply-to) |
| | | * |
| | | * @param reply åå¤å°å(reply-to)å表 |
| | | * @return this |
| | | * @since 4.6.0 |
| | | */ |
| | | public Mail setReply(String... reply) { |
| | | this.reply = reply; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置æ é¢ |
| | | * |
| | | * @param title æ é¢ |
| | | * @return this |
| | | */ |
| | | public Mail setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * è®¾ç½®æ£æ<br> |
| | | * æ£æå¯ä»¥æ¯æ®éææ¬ä¹å¯ä»¥æ¯HTMLï¼é»è®¤æ®éææ¬ï¼ï¼å¯ä»¥éè¿è°ç¨{@link #setHtml(boolean)} 设置æ¯å¦ä¸ºHTML |
| | | * |
| | | * @param content æ£æ |
| | | * @return this |
| | | */ |
| | | public Mail setContent(String content) { |
| | | this.content = content; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置æ¯å¦æ¯HTML |
| | | * |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @return this |
| | | */ |
| | | public Mail setHtml(boolean isHtml) { |
| | | this.isHtml = isHtml; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * è®¾ç½®æ£æ |
| | | * |
| | | * @param content æ£æå
容 |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @return this |
| | | */ |
| | | public Mail setContent(String content, boolean isHtml) { |
| | | setContent(content); |
| | | return setHtml(isHtml); |
| | | } |
| | | |
| | | /** |
| | | * 设置æä»¶ç±»åéä»¶ï¼æä»¶å¯ä»¥æ¯å¾çæä»¶ï¼æ¤æ¶èªå¨è®¾ç½®cidï¼æ£æä¸å¼ç¨å¾çï¼ï¼é»è®¤cid为æä»¶å |
| | | * |
| | | * @param files éä»¶æä»¶å表 |
| | | * @return this |
| | | */ |
| | | public Mail setFiles(File... files) { |
| | | if (ArrayUtil.isEmpty(files)) { |
| | | return this; |
| | | } |
| | | |
| | | final DataSource[] attachments = new DataSource[files.length]; |
| | | for (int i = 0; i < files.length; i++) { |
| | | attachments[i] = new FileDataSource(files[i]); |
| | | } |
| | | return setAttachments(attachments); |
| | | } |
| | | |
| | | /** |
| | | * å¢å éä»¶æå¾çï¼é件使ç¨{@link DataSource} å½¢å¼è¡¨ç¤ºï¼å¯ä»¥ä½¿ç¨{@link FileDataSource}å
è£
æä»¶è¡¨ç¤ºæä»¶éä»¶ |
| | | * |
| | | * @param attachments éä»¶å表 |
| | | * @return this |
| | | * @since 4.0.9 |
| | | */ |
| | | public Mail setAttachments(DataSource... attachments) { |
| | | if (ArrayUtil.isNotEmpty(attachments)) { |
| | | final Charset charset = this.mailAccount.getCharset(); |
| | | MimeBodyPart bodyPart; |
| | | String nameEncoded; |
| | | try { |
| | | for (DataSource attachment : attachments) { |
| | | bodyPart = new MimeBodyPart(); |
| | | bodyPart.setDataHandler(new DataHandler(attachment)); |
| | | nameEncoded = attachment.getName(); |
| | | if (this.mailAccount.isEncodefilename()) { |
| | | nameEncoded = org.dromara.common.mail.utils.InternalMailUtil.encodeText(nameEncoded, charset); |
| | | } |
| | | // æ®ééä»¶æä»¶å |
| | | bodyPart.setFileName(nameEncoded); |
| | | if (StrUtil.startWith(attachment.getContentType(), "image/")) { |
| | | // å¾çéä»¶ï¼ç¨äºæ£æä¸å¼ç¨å¾ç |
| | | bodyPart.setContentID(nameEncoded); |
| | | } |
| | | this.multipart.addBodyPart(bodyPart); |
| | | } |
| | | } catch (MessagingException e) { |
| | | throw new MailException(e); |
| | | } |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * å¢å å¾çï¼å¾ççé®å¯¹åºå°é®ä»¶æ¨¡æ¿ä¸çå ä½å符串ï¼å¾çç±»åé»è®¤ä¸º"image/jpeg" |
| | | * |
| | | * @param cid å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:${cid} |
| | | * @param imageStream å¾çæä»¶ |
| | | * @return this |
| | | * @since 4.6.3 |
| | | */ |
| | | public Mail addImage(String cid, InputStream imageStream) { |
| | | return addImage(cid, imageStream, null); |
| | | } |
| | | |
| | | /** |
| | | * å¢å å¾çï¼å¾ççé®å¯¹åºå°é®ä»¶æ¨¡æ¿ä¸çå ä½å符串 |
| | | * |
| | | * @param cid å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:${cid} |
| | | * @param imageStream å¾çæµï¼ä¸å
³é |
| | | * @param contentType å¾çç±»åï¼nullèµå¼é»è®¤ç"image/jpeg" |
| | | * @return this |
| | | * @since 4.6.3 |
| | | */ |
| | | public Mail addImage(String cid, InputStream imageStream, String contentType) { |
| | | ByteArrayDataSource imgSource; |
| | | try { |
| | | imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg")); |
| | | } catch (IOException e) { |
| | | throw new IORuntimeException(e); |
| | | } |
| | | imgSource.setName(cid); |
| | | return setAttachments(imgSource); |
| | | } |
| | | |
| | | /** |
| | | * å¢å å¾çï¼å¾ççé®å¯¹åºå°é®ä»¶æ¨¡æ¿ä¸çå ä½å符串 |
| | | * |
| | | * @param cid å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:${cid} |
| | | * @param imageFile å¾çæä»¶ |
| | | * @return this |
| | | * @since 4.6.3 |
| | | */ |
| | | public Mail addImage(String cid, File imageFile) { |
| | | InputStream in = null; |
| | | try { |
| | | in = FileUtil.getInputStream(imageFile); |
| | | return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile)); |
| | | } finally { |
| | | IoUtil.close(in); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 设置å符éç¼ç |
| | | * |
| | | * @param charset å符éç¼ç |
| | | * @return this |
| | | * @see MailAccount#setCharset(Charset) |
| | | */ |
| | | public Mail setCharset(Charset charset) { |
| | | this.mailAccount.setCharset(charset); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置æ¯å¦ä½¿ç¨å
¨å±ä¼è¯ï¼é»è®¤ä¸ºtrue |
| | | * |
| | | * @param isUseGlobalSession æ¯å¦ä½¿ç¨å
¨å±ä¼è¯ï¼é»è®¤ä¸ºtrue |
| | | * @return this |
| | | * @since 4.0.2 |
| | | */ |
| | | public Mail setUseGlobalSession(boolean isUseGlobalSession) { |
| | | this.useGlobalSession = isUseGlobalSession; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置debugè¾åºä½ç½®ï¼å¯ä»¥èªå®ä¹debugæ¥å¿ |
| | | * |
| | | * @param debugOutput debugè¾åºä½ç½® |
| | | * @return this |
| | | * @since 5.5.6 |
| | | */ |
| | | public Mail setDebugOutput(PrintStream debugOutput) { |
| | | this.debugOutput = debugOutput; |
| | | return this; |
| | | } |
| | | // --------------------------------------------------------------- Getters and Setters end |
| | | |
| | | @Override |
| | | public MimeMessage build() { |
| | | try { |
| | | return buildMsg(); |
| | | } catch (MessagingException e) { |
| | | throw new MailException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åé |
| | | * |
| | | * @return message-id |
| | | * @throws MailException é®ä»¶åéå¼å¸¸ |
| | | */ |
| | | public String send() throws MailException { |
| | | try { |
| | | return doSend(); |
| | | } catch (MessagingException e) { |
| | | if (e instanceof SendFailedException) { |
| | | // å½å°åæ ææ¶ï¼æ¾ç¤ºæ´å 详ç»çæ æå°åä¿¡æ¯ |
| | | final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses(); |
| | | final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses)); |
| | | throw new MailException(msg, e); |
| | | } |
| | | throw new MailException(e); |
| | | } |
| | | } |
| | | |
| | | // --------------------------------------------------------------- Private method start |
| | | |
| | | /** |
| | | * æ§è¡åé |
| | | * |
| | | * @return message-id |
| | | * @throws MessagingException åéå¼å¸¸ |
| | | */ |
| | | private String doSend() throws MessagingException { |
| | | final MimeMessage mimeMessage = buildMsg(); |
| | | Transport.send(mimeMessage); |
| | | return mimeMessage.getMessageID(); |
| | | } |
| | | |
| | | /** |
| | | * æå»ºæ¶æ¯ |
| | | * |
| | | * @return {@link MimeMessage}æ¶æ¯ |
| | | * @throws MessagingException æ¶æ¯å¼å¸¸ |
| | | */ |
| | | private MimeMessage buildMsg() throws MessagingException { |
| | | final Charset charset = this.mailAccount.getCharset(); |
| | | final MimeMessage msg = new MimeMessage(getSession()); |
| | | // å件人 |
| | | final String from = this.mailAccount.getFrom(); |
| | | if (StrUtil.isEmpty(from)) { |
| | | // ç¨æ·æªæä¾åéæ¹ï¼åä»Sessionä¸èªå¨è·å |
| | | msg.setFrom(); |
| | | } else { |
| | | msg.setFrom(org.dromara.common.mail.utils.InternalMailUtil.parseFirstAddress(from, charset)); |
| | | } |
| | | // æ é¢ |
| | | msg.setSubject(this.title, (null == charset) ? null : charset.name()); |
| | | // åéæ¶é´ |
| | | msg.setSentDate(new Date()); |
| | | // å
容åéä»¶ |
| | | msg.setContent(buildContent(charset)); |
| | | // æ¶ä»¶äºº |
| | | msg.setRecipients(MimeMessage.RecipientType.TO, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.tos, charset)); |
| | | // æé人 |
| | | if (ArrayUtil.isNotEmpty(this.ccs)) { |
| | | msg.setRecipients(MimeMessage.RecipientType.CC, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.ccs, charset)); |
| | | } |
| | | // å¯é人 |
| | | if (ArrayUtil.isNotEmpty(this.bccs)) { |
| | | msg.setRecipients(MimeMessage.RecipientType.BCC, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.bccs, charset)); |
| | | } |
| | | // åå¤å°å(reply-to) |
| | | if (ArrayUtil.isNotEmpty(this.reply)) { |
| | | msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset)); |
| | | } |
| | | |
| | | return msg; |
| | | } |
| | | |
| | | /** |
| | | * æå»ºé®ä»¶ä¿¡æ¯ä¸»ä½ |
| | | * |
| | | * @param charset ç¼ç ï¼{@code null}å使ç¨{@link MimeUtility#getDefaultJavaCharset()} |
| | | * @return é®ä»¶ä¿¡æ¯ä¸»ä½ |
| | | * @throws MessagingException æ¶æ¯å¼å¸¸ |
| | | */ |
| | | private Multipart buildContent(Charset charset) throws MessagingException { |
| | | final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset(); |
| | | // æ£æ |
| | | final MimeBodyPart body = new MimeBodyPart(); |
| | | body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr)); |
| | | this.multipart.addBodyPart(body); |
| | | |
| | | return this.multipart; |
| | | } |
| | | |
| | | /** |
| | | * è·åé»è®¤é®ä»¶ä¼è¯<br> |
| | | * å¦æä¸ºå
¨å±åä¾çä¼è¯ï¼åå
¨å±åªå
许ä¸ä¸ªé®ä»¶å¸å·ï¼å¦åæ¯æ¬¡åéé®ä»¶ä¼æ°å»ºä¸ä¸ªæ°çä¼è¯ |
| | | * |
| | | * @return é®ä»¶ä¼è¯ {@link Session} |
| | | */ |
| | | private Session getSession() { |
| | | final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession); |
| | | |
| | | if (null != this.debugOutput) { |
| | | session.setDebugOut(debugOutput); |
| | | } |
| | | |
| | | return session; |
| | | } |
| | | // --------------------------------------------------------------- Private method end |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.map.MapUtil; |
| | | import cn.hutool.core.util.CharUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.extra.mail.*; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import jakarta.mail.Authenticator; |
| | | import jakarta.mail.Session; |
| | | |
| | | import java.io.File; |
| | | import java.io.InputStream; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | |
| | | /** |
| | | * é®ä»¶å·¥å
·ç±» |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class MailUtils { |
| | | |
| | | private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class); |
| | | |
| | | /** |
| | | * è·åé®ä»¶åéå®ä¾ |
| | | */ |
| | | public static MailAccount getMailAccount() { |
| | | return ACCOUNT; |
| | | } |
| | | |
| | | /** |
| | | * è·åé®ä»¶åéå®ä¾ (èªå®ä¹åéäººä»¥åææç ) |
| | | * |
| | | * @param user åé人 |
| | | * @param pass ææç |
| | | */ |
| | | public static MailAccount getMailAccount(String from, String user, String pass) { |
| | | ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom())); |
| | | ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser())); |
| | | ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass())); |
| | | return ACCOUNT; |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéææ¬é®ä»¶ï¼åéç»å个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººå¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äºº |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String sendText(String to, String subject, String content, File... files) { |
| | | return send(to, subject, content, false, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéHTMLé®ä»¶ï¼åéç»å个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººå¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äºº |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String sendHtml(String to, String subject, String content, File... files) { |
| | | return send(to, subject, content, true, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéå个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººå¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äºº |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String send(String to, String subject, String content, boolean isHtml, File... files) { |
| | | return send(splitAddress(to), subject, content, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéå个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººãæé人ãå¯é人å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äººï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param cc æé人ï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param bcc å¯é人ï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.0.3 |
| | | */ |
| | | public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) { |
| | | return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéææ¬é®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String sendText(Collection<String> tos, String subject, String content, File... files) { |
| | | return send(tos, subject, content, false, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéHTMLé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String sendHtml(Collection<String> tos, String subject, String content, File... files) { |
| | | return send(tos, subject, content, true, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String send(Collection<String> tos, String subject, String content, boolean isHtml, File... files) { |
| | | return send(tos, null, null, subject, content, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param ccs æé人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param bccs å¯é人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.0.3 |
| | | */ |
| | | public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) { |
| | | return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files); |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶è®¤è¯å¯¹è±¡ |
| | | * @param to æ¶ä»¶äººï¼å¤ä¸ªæ¶ä»¶äººéå·æè
åå·éå¼ |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) { |
| | | return send(mailAccount, splitAddress(to), subject, content, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ä¿¡æ¯ |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files) { |
| | | return send(mailAccount, tos, null, null, subject, content, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ä¿¡æ¯ |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param ccs æé人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param bccs å¯é人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.0.3 |
| | | */ |
| | | public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) { |
| | | return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéHTMLé®ä»¶ï¼åéç»å个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººå¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äºº |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String sendHtml(String to, String subject, String content, Map<String, InputStream> imageMap, File... files) { |
| | | return send(to, subject, content, imageMap, true, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéå个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººå¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äºº |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(splitAddress(to), subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéå个æå¤ä¸ªæ¶ä»¶äºº<br> |
| | | * å¤ä¸ªæ¶ä»¶äººãæé人ãå¯é人å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * |
| | | * @param to æ¶ä»¶äººï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param cc æé人ï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param bcc å¯é人ï¼å¯ä»¥ä½¿ç¨éå·â,âåéï¼ä¹å¯ä»¥éè¿åå·â;âåé |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.0.3 |
| | | */ |
| | | public static String send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéHTMLé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String sendHtml(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, File... files) { |
| | | return send(tos, subject, content, imageMap, true, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | */ |
| | | public static String send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(tos, null, null, subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨é
ç½®æä»¶ä¸è®¾ç½®çè´¦æ·åéé®ä»¶ï¼åéç»å¤äºº |
| | | * |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param ccs æé人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param bccs å¯é人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTML |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.0.3 |
| | | */ |
| | | public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶è®¤è¯å¯¹è±¡ |
| | | * @param to æ¶ä»¶äººï¼å¤ä¸ªæ¶ä»¶äººéå·æè
åå·éå¼ |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 3.2.0 |
| | | */ |
| | | public static String send(MailAccount mailAccount, String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ä¿¡æ¯ |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.6.3 |
| | | */ |
| | | public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ä¿¡æ¯ |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param ccs æé人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param bccs å¯é人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:$IMAGE_PLACEHOLDER |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.6.3 |
| | | */ |
| | | public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, |
| | | boolean isHtml, File... files) { |
| | | return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®é
ç½®æä»¶ï¼è·åé®ä»¶å®¢æ·ç«¯ä¼è¯ |
| | | * |
| | | * @param mailAccount é®ä»¶è´¦æ·é
ç½® |
| | | * @param isSingleton æ¯å¦åä¾ï¼å
¨å±å
±äº«ä¼è¯ï¼ |
| | | * @return {@link Session} |
| | | * @since 5.5.7 |
| | | */ |
| | | public static Session getSession(MailAccount mailAccount, boolean isSingleton) { |
| | | Authenticator authenticator = null; |
| | | if (mailAccount.isAuth()) { |
| | | authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); |
| | | } |
| | | |
| | | return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // |
| | | : Session.getInstance(mailAccount.getSmtpProps(), authenticator); |
| | | } |
| | | |
| | | // ------------------------------------------------------------------------------------------------------------------------ Private method start |
| | | |
| | | /** |
| | | * åéé®ä»¶ç»å¤äºº |
| | | * |
| | | * @param mailAccount é®ä»¶å¸æ·ä¿¡æ¯ |
| | | * @param useGlobalSession æ¯å¦å
¨å±å
񄧮Session |
| | | * @param tos æ¶ä»¶äººå表 |
| | | * @param ccs æé人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param bccs å¯é人å表ï¼å¯ä»¥ä¸ºnullæç©º |
| | | * @param subject æ é¢ |
| | | * @param content æ£æ |
| | | * @param imageMap å¾çä¸å ä½ç¬¦ï¼å ä½ç¬¦æ ¼å¼ä¸ºcid:${cid} |
| | | * @param isHtml æ¯å¦ä¸ºHTMLæ ¼å¼ |
| | | * @param files éä»¶å表 |
| | | * @return message-id |
| | | * @since 4.6.3 |
| | | */ |
| | | private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, |
| | | Map<String, InputStream> imageMap, boolean isHtml, File... files) { |
| | | final org.dromara.common.mail.utils.Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession); |
| | | |
| | | // å¯éæé人 |
| | | if (CollUtil.isNotEmpty(ccs)) { |
| | | mail.setCcs(ccs.toArray(new String[0])); |
| | | } |
| | | // å¯éå¯é人 |
| | | if (CollUtil.isNotEmpty(bccs)) { |
| | | mail.setBccs(bccs.toArray(new String[0])); |
| | | } |
| | | |
| | | mail.setTos(tos.toArray(new String[0])); |
| | | mail.setTitle(subject); |
| | | mail.setContent(content); |
| | | mail.setHtml(isHtml); |
| | | mail.setFiles(files); |
| | | |
| | | // å¾ç |
| | | if (MapUtil.isNotEmpty(imageMap)) { |
| | | for (Map.Entry<String, InputStream> entry : imageMap.entrySet()) { |
| | | mail.addImage(entry.getKey(), entry.getValue()); |
| | | // å
³éæµ |
| | | IoUtil.close(entry.getValue()); |
| | | } |
| | | } |
| | | |
| | | return mail.send(); |
| | | } |
| | | |
| | | /** |
| | | * å°å¤ä¸ªè系人转为å表ï¼åé符为éå·æè
åå· |
| | | * |
| | | * @param addresses å¤ä¸ªè系人ï¼å¦æä¸ºç©ºè¿ånull |
| | | * @return è系人å表 |
| | | */ |
| | | private static List<String> splitAddress(String addresses) { |
| | | if (StrUtil.isBlank(addresses)) { |
| | | return null; |
| | | } |
| | | |
| | | List<String> result; |
| | | if (StrUtil.contains(addresses, CharUtil.COMMA)) { |
| | | result = StrUtil.splitTrim(addresses, CharUtil.COMMA); |
| | | } else if (StrUtil.contains(addresses, ';')) { |
| | | result = StrUtil.splitTrim(addresses, ';'); |
| | | } else { |
| | | result = CollUtil.newArrayList(addresses); |
| | | } |
| | | return result; |
| | | } |
| | | // ------------------------------------------------------------------------------------------------------------------------ Private method end |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mail.utils; |
| | | |
| | | import jakarta.mail.Authenticator; |
| | | import jakarta.mail.PasswordAuthentication; |
| | | |
| | | /** |
| | | * ç¨æ·åå¯ç éªè¯å¨ |
| | | * |
| | | * @author looly |
| | | * @since 3.1.2 |
| | | */ |
| | | public class UserPassAuthenticator extends Authenticator { |
| | | |
| | | private final String user; |
| | | private final String pass; |
| | | |
| | | /** |
| | | * æé |
| | | * |
| | | * @param user ç¨æ·å |
| | | * @param pass å¯ç |
| | | */ |
| | | public UserPassAuthenticator(String user, String pass) { |
| | | this.user = user; |
| | | this.pass = pass; |
| | | } |
| | | |
| | | @Override |
| | | protected PasswordAuthentication getPasswordAuthentication() { |
| | | return new PasswordAuthentication(this.user, this.pass); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.mail.config.MailConfig |
| | | org.dromara.common.mail.config.MailConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-satoken</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.annotation; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * æ°æ®æé |
| | | * |
| | | * ä¸ä¸ªæ³¨è§£åªè½å¯¹åºä¸ä¸ªæ¨¡æ¿ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @Target(ElementType.METHOD) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Documented |
| | | public @interface DataColumn { |
| | | |
| | | /** |
| | | * å ä½ç¬¦å
³é®å |
| | | */ |
| | | String[] key() default "deptName"; |
| | | |
| | | /** |
| | | * å ä½ç¬¦æ¿æ¢å¼ |
| | | */ |
| | | String[] value() default "dept_id"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.annotation; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * æ°æ®æéç» |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @Target({ElementType.METHOD, ElementType.TYPE}) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Documented |
| | | public @interface DataPermission { |
| | | |
| | | DataColumn[] value(); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.config; |
| | | |
| | | import cn.hutool.core.net.NetUtil; |
| | | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
| | | import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; |
| | | import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; |
| | | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| | | import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; |
| | | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
| | | import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler; |
| | | import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor; |
| | | import org.mybatis.spring.annotation.MapperScan; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.transaction.annotation.EnableTransactionManagement; |
| | | |
| | | /** |
| | | * mybatis-plusé
置类(䏿¹æ³¨éææä»¶ä»ç») |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @EnableTransactionManagement(proxyTargetClass = true) |
| | | @AutoConfiguration |
| | | @MapperScan("${mybatis-plus.mapperPackage}") |
| | | public class MybatisPlusConfig { |
| | | |
| | | @Bean |
| | | public MybatisPlusInterceptor mybatisPlusInterceptor() { |
| | | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
| | | // æ°æ®æéå¤ç |
| | | interceptor.addInnerInterceptor(dataPermissionInterceptor()); |
| | | // å页æä»¶ |
| | | interceptor.addInnerInterceptor(paginationInnerInterceptor()); |
| | | // ä¹è§éæä»¶ |
| | | interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); |
| | | return interceptor; |
| | | } |
| | | |
| | | /** |
| | | * æ°æ®æéæ¦æªå¨ |
| | | */ |
| | | public PlusDataPermissionInterceptor dataPermissionInterceptor() { |
| | | return new PlusDataPermissionInterceptor(); |
| | | } |
| | | |
| | | /** |
| | | * å页æä»¶ï¼èªå¨è¯å«æ°æ®åºç±»å |
| | | */ |
| | | public PaginationInnerInterceptor paginationInnerInterceptor() { |
| | | PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); |
| | | // 设置æå¤§å页éå¶æ°éï¼é»è®¤ 500 æ¡ï¼-1 ä¸åéå¶ |
| | | paginationInnerInterceptor.setMaxLimit(-1L); |
| | | // å页åçå |
| | | paginationInnerInterceptor.setOverflow(true); |
| | | return paginationInnerInterceptor; |
| | | } |
| | | |
| | | /** |
| | | * ä¹è§éæä»¶ |
| | | */ |
| | | public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { |
| | | return new OptimisticLockerInnerInterceptor(); |
| | | } |
| | | |
| | | /** |
| | | * å
å¯¹è±¡åæ®µå¡«å
æ§å¶å¨ |
| | | */ |
| | | @Bean |
| | | public MetaObjectHandler metaObjectHandler() { |
| | | return new InjectionMetaObjectHandler(); |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨ç½å¡ä¿¡æ¯ç»å®éªè±çæå¨ |
| | | * 鲿¢é群éªè±IDéå¤ |
| | | */ |
| | | @Bean |
| | | public IdentifierGenerator idGenerator() { |
| | | return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); |
| | | } |
| | | |
| | | /** |
| | | * PaginationInnerInterceptor å页æä»¶ï¼èªå¨è¯å«æ°æ®åºç±»å |
| | | * https://baomidou.com/pages/97710a/ |
| | | * OptimisticLockerInnerInterceptor ä¹è§éæä»¶ |
| | | * https://baomidou.com/pages/0d93c0/ |
| | | * MetaObjectHandler å
å¯¹è±¡åæ®µå¡«å
æ§å¶å¨ |
| | | * https://baomidou.com/pages/4c6bcf/ |
| | | * ISqlInjector sql注å
¥å¨ |
| | | * https://baomidou.com/pages/42ea4a/ |
| | | * BlockAttackInnerInterceptor 妿æ¯å¯¹å
¨è¡¨çå é¤ææ´æ°æä½ï¼å°±ä¼ç»æ¢è¯¥æä½ |
| | | * https://baomidou.com/pages/f9a237/ |
| | | * IllegalSQLInnerInterceptor sqlæ§è½è§èæä»¶(åå¾SQLæ¦æª) |
| | | * IdentifierGenerator èªå®ä¹ä¸»é®çç¥ |
| | | * https://baomidou.com/pages/568eb2/ |
| | | * TenantLineInnerInterceptor å¤ç§æ·æä»¶ |
| | | * https://baomidou.com/pages/aef2f2/ |
| | | * DynamicTableNameInnerInterceptor å¨æè¡¨åæä»¶ |
| | | * https://baomidou.com/pages/2a45ff/ |
| | | */ |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.core.domain; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.FieldFill; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.fasterxml.jackson.annotation.JsonIgnore; |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Entityåºç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class BaseEntity implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * æç´¢å¼ |
| | | */ |
| | | @JsonIgnore |
| | | @TableField(exist = false) |
| | | private String searchValue; |
| | | |
| | | /** |
| | | * å建é¨é¨ |
| | | */ |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createDept; |
| | | |
| | | /** |
| | | * å建è
|
| | | */ |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Long createBy; |
| | | |
| | | /** |
| | | * å建æ¶é´ |
| | | */ |
| | | @TableField(fill = FieldFill.INSERT) |
| | | private Date createTime; |
| | | |
| | | /** |
| | | * æ´æ°è
|
| | | */ |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateBy; |
| | | |
| | | /** |
| | | * æ´æ°æ¶é´ |
| | | */ |
| | | @TableField(fill = FieldFill.INSERT_UPDATE) |
| | | private Date updateTime; |
| | | |
| | | /** |
| | | * 请æ±åæ° |
| | | */ |
| | | @JsonInclude(JsonInclude.Include.NON_EMPTY) |
| | | @TableField(exist = false) |
| | | private Map<String, Object> params = new HashMap<>(); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.core.mapper; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.toolkit.Db; |
| | | import org.dromara.common.core.utils.MapstructUtils; |
| | | import org.apache.ibatis.logging.Log; |
| | | import org.apache.ibatis.logging.LogFactory; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * èªå®ä¹ Mapper æ¥å£, å®ç° èªå®ä¹æ©å± |
| | | * |
| | | * @param <T> table æ³å |
| | | * @param <V> vo æ³å |
| | | * @author Lion Li |
| | | * @since 2021-05-13 |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public interface BaseMapperPlus<T, V> extends BaseMapper<T> { |
| | | |
| | | Log log = LogFactory.getLog(BaseMapperPlus.class); |
| | | |
| | | default Class<V> currentVoClass() { |
| | | return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); |
| | | } |
| | | |
| | | default Class<T> currentModelClass() { |
| | | return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); |
| | | } |
| | | |
| | | default List<T> selectList() { |
| | | return this.selectList(new QueryWrapper<>()); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæå
¥ |
| | | */ |
| | | default boolean insertBatch(Collection<T> entityList) { |
| | | return Db.saveBatch(entityList); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæ´æ° |
| | | */ |
| | | default boolean updateBatchById(Collection<T> entityList) { |
| | | return Db.updateBatchById(entityList); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæå
¥ææ´æ° |
| | | */ |
| | | default boolean insertOrUpdateBatch(Collection<T> entityList) { |
| | | return Db.saveOrUpdateBatch(entityList); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæå
¥(å
å«éå¶æ¡æ°) |
| | | */ |
| | | default boolean insertBatch(Collection<T> entityList, int batchSize) { |
| | | return Db.saveBatch(entityList, batchSize); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæ´æ°(å
å«éå¶æ¡æ°) |
| | | */ |
| | | default boolean updateBatchById(Collection<T> entityList, int batchSize) { |
| | | return Db.updateBatchById(entityList, batchSize); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éæå
¥ææ´æ°(å
å«éå¶æ¡æ°) |
| | | */ |
| | | default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) { |
| | | return Db.saveOrUpdateBatch(entityList, batchSize); |
| | | } |
| | | |
| | | /** |
| | | * æå
¥ææ´æ°(å
å«éå¶æ¡æ°) |
| | | */ |
| | | default boolean insertOrUpdate(T entity) { |
| | | return Db.saveOrUpdate(entity); |
| | | } |
| | | |
| | | default V selectVoById(Serializable id) { |
| | | return selectVoById(id, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ® ID æ¥è¯¢ |
| | | */ |
| | | default <C> C selectVoById(Serializable id, Class<C> voClass) { |
| | | T obj = this.selectById(id); |
| | | if (ObjectUtil.isNull(obj)) { |
| | | return null; |
| | | } |
| | | return MapstructUtils.convert(obj, voClass); |
| | | } |
| | | |
| | | default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) { |
| | | return selectVoBatchIds(idList, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢ï¼æ ¹æ®ID æ¹éæ¥è¯¢ï¼ |
| | | */ |
| | | default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) { |
| | | List<T> list = this.selectBatchIds(idList); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | return MapstructUtils.convert(list, voClass); |
| | | } |
| | | |
| | | default List<V> selectVoByMap(Map<String, Object> map) { |
| | | return selectVoByMap(map, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢ï¼æ ¹æ® columnMap æ¡ä»¶ï¼ |
| | | */ |
| | | default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) { |
| | | List<T> list = this.selectByMap(map); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | return MapstructUtils.convert(list, voClass); |
| | | } |
| | | |
| | | default V selectVoOne(Wrapper<T> wrapper) { |
| | | return selectVoOne(wrapper, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ® entity æ¡ä»¶ï¼æ¥è¯¢ä¸æ¡è®°å½ |
| | | */ |
| | | default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) { |
| | | T obj = this.selectOne(wrapper); |
| | | if (ObjectUtil.isNull(obj)) { |
| | | return null; |
| | | } |
| | | return MapstructUtils.convert(obj, voClass); |
| | | } |
| | | |
| | | default List<V> selectVoList() { |
| | | return selectVoList(new QueryWrapper<>(), this.currentVoClass()); |
| | | } |
| | | |
| | | default List<V> selectVoList(Wrapper<T> wrapper) { |
| | | return selectVoList(wrapper, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ® entity æ¡ä»¶ï¼æ¥è¯¢å
¨é¨è®°å½ |
| | | */ |
| | | default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) { |
| | | List<T> list = this.selectList(wrapper); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return CollUtil.newArrayList(); |
| | | } |
| | | return MapstructUtils.convert(list, voClass); |
| | | } |
| | | |
| | | default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) { |
| | | return selectVoPage(page, wrapper, this.currentVoClass()); |
| | | } |
| | | |
| | | /** |
| | | * å页æ¥è¯¢VO |
| | | */ |
| | | default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) { |
| | | IPage<T> pageData = this.selectPage(page, wrapper); |
| | | IPage<C> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); |
| | | if (CollUtil.isEmpty(pageData.getRecords())) { |
| | | return (P) voPage; |
| | | } |
| | | voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass)); |
| | | return (P) voPage; |
| | | } |
| | | |
| | | default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) { |
| | | return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.core.page; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.metadata.OrderItem; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.core.utils.sql.SqlUtil; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢å®ä½ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | public class PageQuery implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * åé¡µå¤§å° |
| | | */ |
| | | private Integer pageSize; |
| | | |
| | | /** |
| | | * å½åé¡µæ° |
| | | */ |
| | | private Integer pageNum; |
| | | |
| | | /** |
| | | * æåºå |
| | | */ |
| | | private String orderByColumn; |
| | | |
| | | /** |
| | | * æåºçæ¹ådescæè
asc |
| | | */ |
| | | private String isAsc; |
| | | |
| | | /** |
| | | * å½åè®°å½èµ·å§ç´¢å¼ é»è®¤å¼ |
| | | */ |
| | | public static final int DEFAULT_PAGE_NUM = 1; |
| | | |
| | | /** |
| | | * æ¯é¡µæ¾ç¤ºè®°å½æ° é»è®¤å¼ é»è®¤æ¥å
¨é¨ |
| | | */ |
| | | public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; |
| | | |
| | | public <T> Page<T> build() { |
| | | Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); |
| | | Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); |
| | | if (pageNum <= 0) { |
| | | pageNum = DEFAULT_PAGE_NUM; |
| | | } |
| | | Page<T> page = new Page<>(pageNum, pageSize); |
| | | List<OrderItem> orderItems = buildOrderItem(); |
| | | if (CollUtil.isNotEmpty(orderItems)) { |
| | | page.addOrder(orderItems); |
| | | } |
| | | return page; |
| | | } |
| | | |
| | | /** |
| | | * æå»ºæåº |
| | | * |
| | | * æ¯æçç¨æ³å¦ä¸: |
| | | * {isAsc:"asc",orderByColumn:"id"} order by id asc |
| | | * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc |
| | | * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc |
| | | * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc |
| | | */ |
| | | private List<OrderItem> buildOrderItem() { |
| | | if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { |
| | | return null; |
| | | } |
| | | String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); |
| | | orderBy = StringUtils.toUnderScoreCase(orderBy); |
| | | |
| | | // å
¼å®¹å端æåºç±»å |
| | | isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); |
| | | |
| | | String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); |
| | | String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); |
| | | if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { |
| | | throw new ServiceException("æåºåæ°æè¯¯"); |
| | | } |
| | | |
| | | List<OrderItem> list = new ArrayList<>(); |
| | | // æ¯ä¸ªå段åèªæåº |
| | | for (int i = 0; i < orderByArr.length; i++) { |
| | | String orderByStr = orderByArr[i]; |
| | | String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; |
| | | if ("asc".equals(isAscStr)) { |
| | | list.add(OrderItem.asc(orderByStr)); |
| | | } else if ("desc".equals(isAscStr)) { |
| | | list.add(OrderItem.desc(orderByStr)); |
| | | } else { |
| | | throw new ServiceException("æåºåæ°æè¯¯"); |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.core.page; |
| | | |
| | | import cn.hutool.http.HttpStatus; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * è¡¨æ ¼åé¡µæ°æ®å¯¹è±¡ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class TableDataInfo<T> implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * æ»è®°å½æ° |
| | | */ |
| | | private long total; |
| | | |
| | | /** |
| | | * åè¡¨æ°æ® |
| | | */ |
| | | private List<T> rows; |
| | | |
| | | /** |
| | | * æ¶æ¯ç¶æç |
| | | */ |
| | | private int code; |
| | | |
| | | /** |
| | | * æ¶æ¯å
容 |
| | | */ |
| | | private String msg; |
| | | |
| | | /** |
| | | * å页 |
| | | * |
| | | * @param list åè¡¨æ°æ® |
| | | * @param total æ»è®°å½æ° |
| | | */ |
| | | public TableDataInfo(List<T> list, long total) { |
| | | this.rows = list; |
| | | this.total = total; |
| | | } |
| | | |
| | | public static <T> TableDataInfo<T> build(IPage<T> page) { |
| | | TableDataInfo<T> rspData = new TableDataInfo<>(); |
| | | rspData.setCode(HttpStatus.HTTP_OK); |
| | | rspData.setMsg("æ¥è¯¢æå"); |
| | | rspData.setRows(page.getRecords()); |
| | | rspData.setTotal(page.getTotal()); |
| | | return rspData; |
| | | } |
| | | |
| | | public static <T> TableDataInfo<T> build(List<T> list) { |
| | | TableDataInfo<T> rspData = new TableDataInfo<>(); |
| | | rspData.setCode(HttpStatus.HTTP_OK); |
| | | rspData.setMsg("æ¥è¯¢æå"); |
| | | rspData.setRows(list); |
| | | rspData.setTotal(list.size()); |
| | | return rspData; |
| | | } |
| | | |
| | | public static <T> TableDataInfo<T> build() { |
| | | TableDataInfo<T> rspData = new TableDataInfo<>(); |
| | | rspData.setCode(HttpStatus.HTTP_OK); |
| | | rspData.setMsg("æ¥è¯¢æå"); |
| | | return rspData; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.enums; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * æ°æ®åºç±»å |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum DataBaseType { |
| | | |
| | | /** |
| | | * MySQL |
| | | */ |
| | | MY_SQL("MySQL"), |
| | | |
| | | /** |
| | | * Oracle |
| | | */ |
| | | ORACLE("Oracle"), |
| | | |
| | | /** |
| | | * PostgreSQL |
| | | */ |
| | | POSTGRE_SQL("PostgreSQL"), |
| | | |
| | | /** |
| | | * SQL Server |
| | | */ |
| | | SQL_SERVER("Microsoft SQL Server"); |
| | | |
| | | private final String type; |
| | | |
| | | public static DataBaseType find(String databaseProductName) { |
| | | if (StringUtils.isBlank(databaseProductName)) { |
| | | return null; |
| | | } |
| | | for (DataBaseType type : values()) { |
| | | if (type.getType().equals(databaseProductName)) { |
| | | return type; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.enums; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | import org.dromara.common.mybatis.helper.DataPermissionHelper; |
| | | |
| | | /** |
| | | * æ°æ®æéç±»å |
| | | * <p> |
| | | * è¯æ³æ¯æ spel 模æ¿è¡¨è¾¾å¼ |
| | | * <p> |
| | | * å
ç½®æ°æ® user å½åç¨æ· å
容åè LoginUser |
| | | * å¦éæ©å±æ°æ® å¯ä½¿ç¨ {@link DataPermissionHelper} æä½ |
| | | * å
ç½®æå¡ sdss ç³»ç»æ°æ®æéæå¡ å
容åè SysDataScopeService |
| | | * å¦éæ©å±æ´å¤èªå®ä¹æå¡ å¯ä»¥åè sdss èªè¡ç¼å |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum DataScopeType { |
| | | |
| | | /** |
| | | * å
¨é¨æ°æ®æé |
| | | */ |
| | | ALL("1", "", ""), |
| | | |
| | | /** |
| | | * èªå®æ°æ®æé |
| | | */ |
| | | CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""), |
| | | |
| | | /** |
| | | * é¨é¨æ°æ®æé |
| | | */ |
| | | DEPT("3", " #{#deptName} = #{#user.deptId} ", ""), |
| | | |
| | | /** |
| | | * é¨é¨å以䏿°æ®æé |
| | | */ |
| | | DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""), |
| | | |
| | | /** |
| | | * ä»
æ¬äººæ°æ®æé |
| | | */ |
| | | SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); |
| | | |
| | | private final String code; |
| | | |
| | | /** |
| | | * è¯æ³ éç¨ spel 模æ¿è¡¨è¾¾å¼ |
| | | */ |
| | | private final String sqlTemplate; |
| | | |
| | | /** |
| | | * 䏿»¡è¶³ sqlTemplate åå¡«å
|
| | | */ |
| | | private final String elseSql; |
| | | |
| | | public static DataScopeType findCode(String code) { |
| | | if (StringUtils.isBlank(code)) { |
| | | return null; |
| | | } |
| | | for (DataScopeType type : values()) { |
| | | if (type.getCode().equals(code)) { |
| | | return type; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.handler; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.http.HttpStatus; |
| | | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.mybatis.core.domain.BaseEntity; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.ibatis.reflection.MetaObject; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * MP注å
¥å¤çå¨ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021/4/25 |
| | | */ |
| | | @Slf4j |
| | | public class InjectionMetaObjectHandler implements MetaObjectHandler { |
| | | |
| | | @Override |
| | | public void insertFill(MetaObject metaObject) { |
| | | try { |
| | | if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { |
| | | Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime()) |
| | | ? baseEntity.getCreateTime() : new Date(); |
| | | baseEntity.setCreateTime(current); |
| | | baseEntity.setUpdateTime(current); |
| | | LoginUser loginUser = getLoginUser(); |
| | | if (ObjectUtil.isNotNull(loginUser)) { |
| | | Long userId = ObjectUtil.isNotNull(baseEntity.getCreateBy()) |
| | | ? baseEntity.getCreateBy() : loginUser.getUserId(); |
| | | // å½åå·²ç»å½ ä¸ å建人为空 åå¡«å
|
| | | baseEntity.setCreateBy(userId); |
| | | // å½åå·²ç»å½ ä¸ æ´æ°äººä¸ºç©º åå¡«å
|
| | | baseEntity.setUpdateBy(userId); |
| | | baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept()) |
| | | ? baseEntity.getCreateDept() : loginUser.getDeptId()); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ServiceException("èªå¨æ³¨å
¥å¼å¸¸ => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void updateFill(MetaObject metaObject) { |
| | | try { |
| | | if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { |
| | | Date current = new Date(); |
| | | // æ´æ°æ¶é´å¡«å
(ä¸ç®¡ä¸ºä¸ä¸ºç©º) |
| | | baseEntity.setUpdateTime(current); |
| | | LoginUser loginUser = getLoginUser(); |
| | | // å½åå·²ç»å½ æ´æ°äººå¡«å
(ä¸ç®¡ä¸ºä¸ä¸ºç©º) |
| | | if (ObjectUtil.isNotNull(loginUser)) { |
| | | baseEntity.setUpdateBy(loginUser.getUserId()); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | throw new ServiceException("èªå¨æ³¨å
¥å¼å¸¸ => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·åç»å½ç¨æ·å |
| | | */ |
| | | private LoginUser getLoginUser() { |
| | | LoginUser loginUser; |
| | | try { |
| | | loginUser = LoginHelper.getLoginUser(); |
| | | } catch (Exception e) { |
| | | log.warn("èªå¨æ³¨å
¥è¦å => ç¨æ·æªç»å½"); |
| | | return null; |
| | | } |
| | | return loginUser; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.handler; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.mybatis.spring.MyBatisSystemException; |
| | | import org.springframework.dao.DuplicateKeyException; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | | import org.springframework.web.bind.annotation.RestControllerAdvice; |
| | | |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | |
| | | /** |
| | | * Mybatiså¼å¸¸å¤çå¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @RestControllerAdvice |
| | | public class MybatisExceptionHandler { |
| | | |
| | | /** |
| | | * 䏻鮿UNIQUEç´¢å¼ï¼æ°æ®éå¤å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(DuplicateKeyException.class) |
| | | public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',æ°æ®åºä¸å·²åå¨è®°å½'{}'", requestURI, e.getMessage()); |
| | | return R.fail("æ°æ®åºä¸å·²åå¨è¯¥è®°å½ï¼è¯·è系管çå确认"); |
| | | } |
| | | |
| | | /** |
| | | * Mybatisç³»ç»å¼å¸¸ éç¨å¤ç |
| | | */ |
| | | @ExceptionHandler(MyBatisSystemException.class) |
| | | public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | String message = e.getMessage(); |
| | | if (message.contains("CannotFindDataSourceException")) { |
| | | log.error("请æ±å°å'{}', æªæ¾å°æ°æ®æº", requestURI); |
| | | return R.fail("æªæ¾å°æ°æ®æºï¼è¯·è系管çå确认"); |
| | | } |
| | | log.error("请æ±å°å'{}', Mybatisç³»ç»å¼å¸¸", requestURI, e); |
| | | return R.fail(message); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.handler; |
| | | |
| | | import cn.hutool.core.annotation.AnnotationUtil; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.collection.ConcurrentHashSet; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.ClassUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import org.dromara.common.core.domain.dto.RoleDTO; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StreamUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.mybatis.annotation.DataColumn; |
| | | import org.dromara.common.mybatis.annotation.DataPermission; |
| | | import org.dromara.common.mybatis.enums.DataScopeType; |
| | | import org.dromara.common.mybatis.helper.DataPermissionHelper; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import net.sf.jsqlparser.JSQLParserException; |
| | | import net.sf.jsqlparser.expression.Expression; |
| | | import net.sf.jsqlparser.expression.Parenthesis; |
| | | import net.sf.jsqlparser.expression.operators.conditional.AndExpression; |
| | | import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
| | | import org.springframework.context.expression.BeanFactoryResolver; |
| | | import org.springframework.expression.BeanResolver; |
| | | import org.springframework.expression.ExpressionParser; |
| | | import org.springframework.expression.ParserContext; |
| | | import org.springframework.expression.common.TemplateParserContext; |
| | | import org.springframework.expression.spel.standard.SpelExpressionParser; |
| | | import org.springframework.expression.spel.support.StandardEvaluationContext; |
| | | |
| | | import java.lang.reflect.Method; |
| | | import java.util.*; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.function.Function; |
| | | |
| | | /** |
| | | * æ°æ®æéè¿æ»¤ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @Slf4j |
| | | public class PlusDataPermissionHandler { |
| | | |
| | | /** |
| | | * æ¹æ³æç±»(åç§°) ä¸ æ³¨è§£çæ å°å
³ç³»ç¼å |
| | | */ |
| | | private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * æ ææ³¨è§£æ¹æ³ç¼åç¨äºå¿«éè¿å |
| | | */ |
| | | private final Set<String> invalidCacheSet = new ConcurrentHashSet<>(); |
| | | |
| | | /** |
| | | * spel è§£æå¨ |
| | | */ |
| | | private final ExpressionParser parser = new SpelExpressionParser(); |
| | | private final ParserContext parserContext = new TemplateParserContext(); |
| | | /** |
| | | * beanè§£æå¨ ç¨äºå¤ç spel 表达å¼ä¸å¯¹ bean çè°ç¨ |
| | | */ |
| | | private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); |
| | | |
| | | |
| | | public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { |
| | | DataColumn[] dataColumns = findAnnotation(mappedStatementId); |
| | | if (ArrayUtil.isEmpty(dataColumns)) { |
| | | invalidCacheSet.add(mappedStatementId); |
| | | return where; |
| | | } |
| | | LoginUser currentUser = DataPermissionHelper.getVariable("user"); |
| | | if (ObjectUtil.isNull(currentUser)) { |
| | | currentUser = LoginHelper.getLoginUser(); |
| | | DataPermissionHelper.setVariable("user", currentUser); |
| | | } |
| | | // 妿æ¯è¶
级管çåæç§æ·ç®¡çåï¼åä¸è¿æ»¤æ°æ® |
| | | if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { |
| | | return where; |
| | | } |
| | | String dataFilterSql = buildDataFilter(dataColumns, isSelect); |
| | | if (StringUtils.isBlank(dataFilterSql)) { |
| | | return where; |
| | | } |
| | | try { |
| | | Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); |
| | | // æ°æ®æé使ç¨åç¬çæ¬å· 鲿¢ä¸å
¶ä»æ¡ä»¶å²çª |
| | | Parenthesis parenthesis = new Parenthesis(expression); |
| | | if (ObjectUtil.isNotNull(where)) { |
| | | return new AndExpression(where, parenthesis); |
| | | } else { |
| | | return parenthesis; |
| | | } |
| | | } catch (JSQLParserException e) { |
| | | throw new ServiceException("æ°æ®æéè§£æå¼å¸¸ => " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æé æ°æ®è¿æ»¤sql |
| | | */ |
| | | private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) { |
| | | // æ´æ°æå é¤éæ»¡è¶³æææ¡ä»¶ |
| | | String joinStr = isSelect ? " OR " : " AND "; |
| | | LoginUser user = DataPermissionHelper.getVariable("user"); |
| | | StandardEvaluationContext context = new StandardEvaluationContext(); |
| | | context.setBeanResolver(beanResolver); |
| | | DataPermissionHelper.getContext().forEach(context::setVariable); |
| | | Set<String> conditions = new HashSet<>(); |
| | | for (RoleDTO role : user.getRoles()) { |
| | | user.setRoleId(role.getRoleId()); |
| | | // è·åè§è²æéæ³å |
| | | DataScopeType type = DataScopeType.findCode(role.getDataScope()); |
| | | if (ObjectUtil.isNull(type)) { |
| | | throw new ServiceException("è§è²æ°æ®èå´å¼å¸¸ => " + role.getDataScope()); |
| | | } |
| | | // å
¨é¨æ°æ®æéç´æ¥è¿å |
| | | if (type == DataScopeType.ALL) { |
| | | return ""; |
| | | } |
| | | boolean isSuccess = false; |
| | | for (DataColumn dataColumn : dataColumns) { |
| | | if (dataColumn.key().length != dataColumn.value().length) { |
| | | throw new ServiceException("è§è²æ°æ®èå´å¼å¸¸ => keyä¸valueé¿åº¦ä¸å¹é
"); |
| | | } |
| | | // ä¸å
å« key åé åä¸å¤ç |
| | | if (!StringUtils.containsAny(type.getSqlTemplate(), |
| | | Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new) |
| | | )) { |
| | | continue; |
| | | } |
| | | // 设置注解åé key 为表达å¼åé value 为åéå¼ |
| | | for (int i = 0; i < dataColumn.key().length; i++) { |
| | | context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); |
| | | } |
| | | |
| | | // è§£æsql模æ¿å¹¶å¡«å
|
| | | String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); |
| | | conditions.add(joinStr + sql); |
| | | isSuccess = true; |
| | | } |
| | | // æªå¤çæååå¡«å
å
åºæ¹æ¡ |
| | | if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { |
| | | conditions.add(joinStr + type.getElseSql()); |
| | | } |
| | | } |
| | | |
| | | if (CollUtil.isNotEmpty(conditions)) { |
| | | String sql = StreamUtils.join(conditions, Function.identity(), ""); |
| | | return sql.substring(joinStr.length()); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private DataColumn[] findAnnotation(String mappedStatementId) { |
| | | StringBuilder sb = new StringBuilder(mappedStatementId); |
| | | int index = sb.lastIndexOf("."); |
| | | String clazzName = sb.substring(0, index); |
| | | String methodName = sb.substring(index + 1, sb.length()); |
| | | Class<?> clazz = ClassUtil.loadClass(clazzName); |
| | | List<Method> methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) |
| | | .filter(method -> method.getName().equals(methodName)).toList(); |
| | | DataPermission dataPermission; |
| | | // è·åæ¹æ³æ³¨è§£ |
| | | for (Method method : methods) { |
| | | dataPermission = dataPermissionCacheMap.get(mappedStatementId); |
| | | if (ObjectUtil.isNotNull(dataPermission)) { |
| | | return dataPermission.value(); |
| | | } |
| | | if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { |
| | | dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); |
| | | dataPermissionCacheMap.put(mappedStatementId, dataPermission); |
| | | return dataPermission.value(); |
| | | } |
| | | } |
| | | dataPermission = dataPermissionCacheMap.get(clazz.getName()); |
| | | if (ObjectUtil.isNotNull(dataPermission)) { |
| | | return dataPermission.value(); |
| | | } |
| | | // è·å类注解 |
| | | if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { |
| | | dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); |
| | | dataPermissionCacheMap.put(clazz.getName(), dataPermission); |
| | | return dataPermission.value(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºæ ææ¹æ³ æ æ°æ®æé |
| | | */ |
| | | public boolean isInvalid(String mappedStatementId) { |
| | | return invalidCacheSet.contains(mappedStatementId); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.helper; |
| | | |
| | | import cn.hutool.core.convert.Convert; |
| | | import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.mybatis.enums.DataBaseType; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import javax.sql.DataSource; |
| | | import java.sql.Connection; |
| | | import java.sql.DatabaseMetaData; |
| | | import java.sql.SQLException; |
| | | |
| | | /** |
| | | * æ°æ®åºå©æ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class DataBaseHelper { |
| | | |
| | | private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); |
| | | |
| | | /** |
| | | * è·åå½åæ°æ®åºç±»å |
| | | */ |
| | | public static DataBaseType getDataBaseType() { |
| | | DataSource dataSource = DS.determineDataSource(); |
| | | try (Connection conn = dataSource.getConnection()) { |
| | | DatabaseMetaData metaData = conn.getMetaData(); |
| | | String databaseProductName = metaData.getDatabaseProductName(); |
| | | return DataBaseType.find(databaseProductName); |
| | | } catch (SQLException e) { |
| | | throw new ServiceException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | public static boolean isMySql() { |
| | | return DataBaseType.MY_SQL == getDataBaseType(); |
| | | } |
| | | |
| | | public static boolean isOracle() { |
| | | return DataBaseType.ORACLE == getDataBaseType(); |
| | | } |
| | | |
| | | public static boolean isPostgerSql() { |
| | | return DataBaseType.POSTGRE_SQL == getDataBaseType(); |
| | | } |
| | | |
| | | public static boolean isSqlServer() { |
| | | return DataBaseType.SQL_SERVER == getDataBaseType(); |
| | | } |
| | | |
| | | public static String findInSet(Object var1, String var2) { |
| | | DataBaseType dataBasyType = getDataBaseType(); |
| | | String var = Convert.toStr(var1); |
| | | if (dataBasyType == DataBaseType.SQL_SERVER) { |
| | | // charindex(',100,' , ',0,100,101,') <> 0 |
| | | return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); |
| | | } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { |
| | | // (select position(',100,' in ',0,100,101,')) <> 0 |
| | | return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2); |
| | | } else if (dataBasyType == DataBaseType.ORACLE) { |
| | | // instr(',0,100,101,' , ',100,') <> 0 |
| | | return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); |
| | | } |
| | | // find_in_set(100 , '0,100,101') |
| | | return "find_in_set('%s' , %s) <> 0".formatted(var, var2); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.helper; |
| | | |
| | | import cn.dev33.satoken.context.SaHolder; |
| | | import cn.dev33.satoken.context.model.SaStorage; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; |
| | | import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æ°æ®æé婿 |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | @SuppressWarnings("unchecked cast") |
| | | public class DataPermissionHelper { |
| | | |
| | | private static final String DATA_PERMISSION_KEY = "data:permission"; |
| | | |
| | | public static <T> T getVariable(String key) { |
| | | Map<String, Object> context = getContext(); |
| | | return (T) context.get(key); |
| | | } |
| | | |
| | | |
| | | public static void setVariable(String key, Object value) { |
| | | Map<String, Object> context = getContext(); |
| | | context.put(key, value); |
| | | } |
| | | |
| | | public static Map<String, Object> getContext() { |
| | | SaStorage saStorage = SaHolder.getStorage(); |
| | | Object attribute = saStorage.get(DATA_PERMISSION_KEY); |
| | | if (ObjectUtil.isNull(attribute)) { |
| | | saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); |
| | | attribute = saStorage.get(DATA_PERMISSION_KEY); |
| | | } |
| | | if (attribute instanceof Map map) { |
| | | return map; |
| | | } |
| | | throw new NullPointerException("data permission context type exception"); |
| | | } |
| | | |
| | | /** |
| | | * å¼å¯å¿½ç¥æ°æ®æé(å¼å¯åéæå¨è°ç¨ {@link #disableIgnore()} å
³é) |
| | | */ |
| | | public static void enableIgnore() { |
| | | InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); |
| | | } |
| | | |
| | | /** |
| | | * å
³éå¿½ç¥æ°æ®æé |
| | | */ |
| | | public static void disableIgnore() { |
| | | InterceptorIgnoreHelper.clearIgnoreStrategy(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.mybatis.interceptor; |
| | | |
| | | import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; |
| | | import com.baomidou.mybatisplus.core.toolkit.PluginUtils; |
| | | import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; |
| | | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; |
| | | import org.dromara.common.mybatis.handler.PlusDataPermissionHandler; |
| | | import net.sf.jsqlparser.expression.Expression; |
| | | import net.sf.jsqlparser.statement.delete.Delete; |
| | | import net.sf.jsqlparser.statement.select.PlainSelect; |
| | | import net.sf.jsqlparser.statement.select.Select; |
| | | import net.sf.jsqlparser.statement.select.SelectBody; |
| | | import net.sf.jsqlparser.statement.select.SetOperationList; |
| | | import net.sf.jsqlparser.statement.update.Update; |
| | | import org.apache.ibatis.executor.Executor; |
| | | import org.apache.ibatis.executor.statement.StatementHandler; |
| | | import org.apache.ibatis.mapping.BoundSql; |
| | | import org.apache.ibatis.mapping.MappedStatement; |
| | | import org.apache.ibatis.mapping.SqlCommandType; |
| | | import org.apache.ibatis.session.ResultHandler; |
| | | import org.apache.ibatis.session.RowBounds; |
| | | |
| | | import java.sql.Connection; |
| | | import java.sql.SQLException; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ°æ®æéæ¦æªå¨ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { |
| | | |
| | | private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); |
| | | |
| | | @Override |
| | | public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { |
| | | // æ£æ¥å¿½ç¥æ³¨è§£ |
| | | if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { |
| | | return; |
| | | } |
| | | // æ£æ¥æ¯å¦æ æ æ æ°æ®æé注解 |
| | | if (dataPermissionHandler.isInvalid(ms.getId())) { |
| | | return; |
| | | } |
| | | // è§£æ sql åé
å¯¹åºæ¹æ³ |
| | | PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); |
| | | mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); |
| | | } |
| | | |
| | | @Override |
| | | public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { |
| | | PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); |
| | | MappedStatement ms = mpSh.mappedStatement(); |
| | | SqlCommandType sct = ms.getSqlCommandType(); |
| | | if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { |
| | | if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { |
| | | return; |
| | | } |
| | | PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); |
| | | mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void processSelect(Select select, int index, String sql, Object obj) { |
| | | SelectBody selectBody = select.getSelectBody(); |
| | | if (selectBody instanceof PlainSelect) { |
| | | this.setWhere((PlainSelect) selectBody, (String) obj); |
| | | } else if (selectBody instanceof SetOperationList setOperationList) { |
| | | List<SelectBody> selectBodyList = setOperationList.getSelects(); |
| | | selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj)); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void processUpdate(Update update, int index, String sql, Object obj) { |
| | | Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false); |
| | | if (null != sqlSegment) { |
| | | update.setWhere(sqlSegment); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void processDelete(Delete delete, int index, String sql, Object obj) { |
| | | Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false); |
| | | if (null != sqlSegment) { |
| | | delete.setWhere(sqlSegment); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 设置 where æ¡ä»¶ |
| | | * |
| | | * @param plainSelect æ¥è¯¢å¯¹è±¡ |
| | | * @param mappedStatementId æ§è¡æ¹æ³id |
| | | */ |
| | | protected void setWhere(PlainSelect plainSelect, String mappedStatementId) { |
| | | Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true); |
| | | if (null != sqlSegment) { |
| | | plainSelect.setWhere(sqlSegment); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | com.ruoyi.common.mybatis.config.MybatisPlusConfig |
| | | org.dromara.common.mybatis.config.MybatisPlusConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.constant; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 对象åå¨å¸¸é |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface OssConstant { |
| | | |
| | | /** |
| | | * é»è®¤é
ç½®KEY |
| | | */ |
| | | String DEFAULT_CONFIG_KEY = "sys_oss:default_config"; |
| | | |
| | | /** |
| | | * é¢è§åè¡¨èµæºå¼å
³Key |
| | | */ |
| | | String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource"; |
| | | |
| | | /** |
| | | * ç³»ç»æ°æ®ids |
| | | */ |
| | | List<Long> SYSTEM_DATA_IDS = Arrays.asList(1L, 2L, 3L, 4L); |
| | | |
| | | /** |
| | | * äºæå¡å |
| | | */ |
| | | String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"}; |
| | | |
| | | /** |
| | | * https ç¶æ |
| | | */ |
| | | String IS_HTTPS = "Y"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.core; |
| | | |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import com.amazonaws.ClientConfiguration; |
| | | import com.amazonaws.HttpMethod; |
| | | import com.amazonaws.Protocol; |
| | | import com.amazonaws.auth.AWSCredentials; |
| | | import com.amazonaws.auth.AWSCredentialsProvider; |
| | | import com.amazonaws.auth.AWSStaticCredentialsProvider; |
| | | import com.amazonaws.auth.BasicAWSCredentials; |
| | | import com.amazonaws.client.builder.AwsClientBuilder; |
| | | import com.amazonaws.services.s3.AmazonS3; |
| | | import com.amazonaws.services.s3.AmazonS3Client; |
| | | import com.amazonaws.services.s3.AmazonS3ClientBuilder; |
| | | import com.amazonaws.services.s3.model.*; |
| | | import org.dromara.common.core.utils.DateUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.oss.constant.OssConstant; |
| | | import org.dromara.common.oss.entity.UploadResult; |
| | | import org.dromara.common.oss.enumd.AccessPolicyType; |
| | | import org.dromara.common.oss.enumd.PolicyType; |
| | | import org.dromara.common.oss.exception.OssException; |
| | | import org.dromara.common.oss.properties.OssProperties; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * S3 åå¨åè®® ææå
¼å®¹S3åè®®çäºåå忝æ |
| | | * é¿éäº è
¾è®¯äº ä¸çäº minio |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class OssClient { |
| | | |
| | | private final String configKey; |
| | | |
| | | private final OssProperties properties; |
| | | |
| | | private final AmazonS3 client; |
| | | |
| | | public OssClient(String configKey, OssProperties ossProperties) { |
| | | this.configKey = configKey; |
| | | this.properties = ossProperties; |
| | | try { |
| | | AwsClientBuilder.EndpointConfiguration endpointConfig = |
| | | new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion()); |
| | | |
| | | AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey()); |
| | | AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); |
| | | ClientConfiguration clientConfig = new ClientConfiguration(); |
| | | if (OssConstant.IS_HTTPS.equals(properties.getIsHttps())) { |
| | | clientConfig.setProtocol(Protocol.HTTPS); |
| | | } else { |
| | | clientConfig.setProtocol(Protocol.HTTP); |
| | | } |
| | | AmazonS3ClientBuilder build = AmazonS3Client.builder() |
| | | .withEndpointConfiguration(endpointConfig) |
| | | .withClientConfiguration(clientConfig) |
| | | .withCredentials(credentialsProvider) |
| | | .disableChunkedEncoding(); |
| | | if (!StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)) { |
| | | // minio 使ç¨httpséå¶ä½¿ç¨ååè®¿é® éè¦æ¤é
ç½® ç«ç¹å¡«åå |
| | | build.enablePathStyleAccess(); |
| | | } |
| | | this.client = build.build(); |
| | | |
| | | createBucket(); |
| | | } catch (Exception e) { |
| | | if (e instanceof OssException) { |
| | | throw e; |
| | | } |
| | | throw new OssException("é
ç½®é误! è¯·æ£æ¥ç³»ç»é
ç½®:[" + e.getMessage() + "]"); |
| | | } |
| | | } |
| | | |
| | | public void createBucket() { |
| | | try { |
| | | String bucketName = properties.getBucketName(); |
| | | if (client.doesBucketExistV2(bucketName)) { |
| | | return; |
| | | } |
| | | CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); |
| | | AccessPolicyType accessPolicy = getAccessPolicy(); |
| | | createBucketRequest.setCannedAcl(accessPolicy.getAcl()); |
| | | client.createBucket(createBucketRequest); |
| | | client.setBucketPolicy(bucketName, getPolicy(bucketName, accessPolicy.getPolicyType())); |
| | | } catch (Exception e) { |
| | | throw new OssException("å建Bucket失败, è¯·æ ¸å¯¹é
置信æ¯:[" + e.getMessage() + "]"); |
| | | } |
| | | } |
| | | |
| | | public UploadResult upload(byte[] data, String path, String contentType) { |
| | | return upload(new ByteArrayInputStream(data), path, contentType); |
| | | } |
| | | |
| | | public UploadResult upload(InputStream inputStream, String path, String contentType) { |
| | | if (!(inputStream instanceof ByteArrayInputStream)) { |
| | | inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream)); |
| | | } |
| | | try { |
| | | ObjectMetadata metadata = new ObjectMetadata(); |
| | | metadata.setContentType(contentType); |
| | | metadata.setContentLength(inputStream.available()); |
| | | PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata); |
| | | // 设置ä¸ä¼ 对象ç Acl 为å
Œ
±è¯» |
| | | putObjectRequest.setCannedAcl(getAccessPolicy().getAcl()); |
| | | client.putObject(putObjectRequest); |
| | | } catch (Exception e) { |
| | | throw new OssException("ä¸ä¼ æä»¶å¤±è´¥ï¼è¯·æ£æ¥é
置信æ¯:[" + e.getMessage() + "]"); |
| | | } |
| | | return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build(); |
| | | } |
| | | |
| | | public void delete(String path) { |
| | | path = path.replace(getUrl() + "/", ""); |
| | | try { |
| | | client.deleteObject(properties.getBucketName(), path); |
| | | } catch (Exception e) { |
| | | throw new OssException("å é¤æä»¶å¤±è´¥ï¼è¯·æ£æ¥é
置信æ¯:[" + e.getMessage() + "]"); |
| | | } |
| | | } |
| | | |
| | | public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { |
| | | return upload(data, getPath(properties.getPrefix(), suffix), contentType); |
| | | } |
| | | |
| | | public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { |
| | | return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); |
| | | } |
| | | |
| | | /** |
| | | * è·åæä»¶å
æ°æ® |
| | | * |
| | | * @param path 宿´æä»¶è·¯å¾ |
| | | */ |
| | | public ObjectMetadata getObjectMetadata(String path) { |
| | | path = path.replace(getUrl() + "/", ""); |
| | | S3Object object = client.getObject(properties.getBucketName(), path); |
| | | return object.getObjectMetadata(); |
| | | } |
| | | |
| | | public InputStream getObjectContent(String path) { |
| | | path = path.replace(getUrl() + "/", ""); |
| | | S3Object object = client.getObject(properties.getBucketName(), path); |
| | | return object.getObjectContent(); |
| | | } |
| | | |
| | | public String getUrl() { |
| | | String domain = properties.getDomain(); |
| | | String endpoint = properties.getEndpoint(); |
| | | String header = OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? "https://" : "http://"; |
| | | // äºæå¡åç´æ¥è¿å |
| | | if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) { |
| | | if (StringUtils.isNotBlank(domain)) { |
| | | return header + domain; |
| | | } |
| | | return header + properties.getBucketName() + "." + endpoint; |
| | | } |
| | | // minio åç¬å¤ç |
| | | if (StringUtils.isNotBlank(domain)) { |
| | | return header + domain + "/" + properties.getBucketName(); |
| | | } |
| | | return header + endpoint + "/" + properties.getBucketName(); |
| | | } |
| | | |
| | | public String getPath(String prefix, String suffix) { |
| | | // çæuuid |
| | | String uuid = IdUtil.fastSimpleUUID(); |
| | | // æä»¶è·¯å¾ |
| | | String path = DateUtils.datePath() + "/" + uuid; |
| | | if (StringUtils.isNotBlank(prefix)) { |
| | | path = prefix + "/" + path; |
| | | } |
| | | return path + suffix; |
| | | } |
| | | |
| | | |
| | | public String getConfigKey() { |
| | | return configKey; |
| | | } |
| | | |
| | | /** |
| | | * è·åç§æURL龿¥ |
| | | * |
| | | * @param objectKey 对象KEY |
| | | * @param second æææ¶é´ |
| | | */ |
| | | public String getPrivateUrl(String objectKey, Integer second) { |
| | | GeneratePresignedUrlRequest generatePresignedUrlRequest = |
| | | new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey) |
| | | .withMethod(HttpMethod.GET) |
| | | .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); |
| | | URL url = client.generatePresignedUrl(generatePresignedUrlRequest); |
| | | return url.toString(); |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥é
ç½®æ¯å¦ç¸å |
| | | */ |
| | | public boolean checkPropertiesSame(OssProperties properties) { |
| | | return this.properties.equals(properties); |
| | | } |
| | | |
| | | /** |
| | | * è·åå½åæ¡¶æéç±»å |
| | | * |
| | | * @return å½åæ¡¶æéç±»åcode |
| | | */ |
| | | public AccessPolicyType getAccessPolicy() { |
| | | return AccessPolicyType.getByType(properties.getAccessPolicy()); |
| | | } |
| | | |
| | | private static String getPolicy(String bucketName, PolicyType policyType) { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n"); |
| | | builder.append(switch (policyType) { |
| | | case WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n"; |
| | | case READ_WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n"; |
| | | default -> "\"s3:GetBucketLocation\"\n"; |
| | | }); |
| | | builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); |
| | | builder.append(bucketName); |
| | | builder.append("\"\n},\n"); |
| | | if (policyType == PolicyType.READ) { |
| | | builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); |
| | | builder.append(bucketName); |
| | | builder.append("\"\n},\n"); |
| | | } |
| | | builder.append("{\n\"Action\": "); |
| | | builder.append(switch (policyType) { |
| | | case WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; |
| | | case READ_WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; |
| | | default -> "\"s3:GetObject\",\n"; |
| | | }); |
| | | builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); |
| | | builder.append(bucketName); |
| | | builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n"); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.entity; |
| | | |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ä¸ä¼ è¿åä½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @Builder |
| | | public class UploadResult { |
| | | |
| | | /** |
| | | * æä»¶è·¯å¾ |
| | | */ |
| | | private String url; |
| | | |
| | | /** |
| | | * æä»¶å |
| | | */ |
| | | private String filename; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.enumd; |
| | | |
| | | import com.amazonaws.services.s3.model.CannedAccessControlList; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * 桶访é®çç¥é
ç½® |
| | | * |
| | | * @author éè³ |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum AccessPolicyType { |
| | | |
| | | /** |
| | | * private |
| | | */ |
| | | PRIVATE("0", CannedAccessControlList.Private, PolicyType.WRITE), |
| | | |
| | | /** |
| | | * public |
| | | */ |
| | | PUBLIC("1", CannedAccessControlList.PublicRead, PolicyType.READ), |
| | | |
| | | /** |
| | | * custom |
| | | */ |
| | | CUSTOM("2",CannedAccessControlList.PublicRead, PolicyType.READ); |
| | | |
| | | /** |
| | | * æ¡¶ æéç±»å |
| | | */ |
| | | private final String type; |
| | | |
| | | /** |
| | | * æä»¶å¯¹è±¡ æéç±»å |
| | | */ |
| | | private final CannedAccessControlList acl; |
| | | |
| | | /** |
| | | * æ¡¶çç¥ç±»å |
| | | */ |
| | | private final PolicyType policyType; |
| | | |
| | | public static AccessPolicyType getByType(String type) { |
| | | for (AccessPolicyType value : values()) { |
| | | if (value.getType().equals(type)) { |
| | | return value; |
| | | } |
| | | } |
| | | throw new RuntimeException("'type' not found By " + type); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.enumd; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * minioçç¥é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum PolicyType { |
| | | |
| | | /** |
| | | * åªè¯» |
| | | */ |
| | | READ("read-only"), |
| | | |
| | | /** |
| | | * åªå |
| | | */ |
| | | WRITE("write-only"), |
| | | |
| | | /** |
| | | * 读å |
| | | */ |
| | | READ_WRITE("read-write"); |
| | | |
| | | /** |
| | | * ç±»å |
| | | */ |
| | | private final String type; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * OSSå¼å¸¸ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class OssException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public OssException(String msg) { |
| | | super(msg); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.factory; |
| | | |
| | | import org.dromara.common.core.constant.CacheNames; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.oss.constant.OssConstant; |
| | | import org.dromara.common.oss.core.OssClient; |
| | | import org.dromara.common.oss.exception.OssException; |
| | | import org.dromara.common.oss.properties.OssProperties; |
| | | import org.dromara.common.redis.utils.CacheUtils; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * æä»¶ä¸ä¼ Factory |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | public class OssFactory { |
| | | |
| | | private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * è·åé»è®¤å®ä¾ |
| | | */ |
| | | public static OssClient instance() { |
| | | // è·åredis é»è®¤ç±»å |
| | | String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY); |
| | | if (StringUtils.isEmpty(configKey)) { |
| | | throw new OssException("æä»¶å卿å¡ç±»åæ æ³æ¾å°!"); |
| | | } |
| | | return instance(configKey); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®ç±»åè·åå®ä¾ |
| | | */ |
| | | public static OssClient instance(String configKey) { |
| | | String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey); |
| | | if (json == null) { |
| | | throw new OssException("ç³»ç»å¼å¸¸, '" + configKey + "'é
置信æ¯ä¸åå¨!"); |
| | | } |
| | | OssProperties properties = JsonUtils.parseObject(json, OssProperties.class); |
| | | OssClient client = CLIENT_CACHE.get(configKey); |
| | | if (client == null) { |
| | | CLIENT_CACHE.put(configKey, new OssClient(configKey, properties)); |
| | | log.info("å建OSSå®ä¾ key => {}", configKey); |
| | | return CLIENT_CACHE.get(configKey); |
| | | } |
| | | // é
ç½®ä¸ç¸ååéæ°æå»º |
| | | if (!client.checkPropertiesSame(properties)) { |
| | | CLIENT_CACHE.put(configKey, new OssClient(configKey, properties)); |
| | | log.info("éè½½OSSå®ä¾ key => {}", configKey); |
| | | return CLIENT_CACHE.get(configKey); |
| | | } |
| | | return client; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.oss.properties; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * OSS对象åå¨ é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | public class OssProperties { |
| | | |
| | | /** |
| | | * 访é®ç«ç¹ |
| | | */ |
| | | private String endpoint; |
| | | |
| | | /** |
| | | * èªå®ä¹åå |
| | | */ |
| | | private String domain; |
| | | |
| | | /** |
| | | * åç¼ |
| | | */ |
| | | private String prefix; |
| | | |
| | | /** |
| | | * ACCESS_KEY |
| | | */ |
| | | private String accessKey; |
| | | |
| | | /** |
| | | * SECRET_KEY |
| | | */ |
| | | private String secretKey; |
| | | |
| | | /** |
| | | * åå¨ç©ºé´å |
| | | */ |
| | | private String bucketName; |
| | | |
| | | /** |
| | | * åå¨åºå |
| | | */ |
| | | private String region; |
| | | |
| | | /** |
| | | * æ¯å¦httpsï¼Y=æ¯,N=å¦ï¼ |
| | | */ |
| | | private String isHttps; |
| | | |
| | | /** |
| | | * æ¡¶æéç±»å(0private 1public 2custom) |
| | | */ |
| | | private String accessPolicy; |
| | | |
| | | } |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | </dependencies> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.ratelimiter.annotation; |
| | | |
| | | import org.dromara.common.ratelimiter.enums.LimitType; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * éæµæ³¨è§£ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Target(ElementType.METHOD) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Documented |
| | | public @interface RateLimiter { |
| | | /** |
| | | * éæµkey,æ¯æä½¿ç¨Spring elè¡¨è¾¾å¼æ¥å¨æè·åæ¹æ³ä¸çåæ°å¼ |
| | | * æ ¼å¼ç±»ä¼¼äº #code.id #{#code} |
| | | */ |
| | | String key() default ""; |
| | | |
| | | /** |
| | | * éæµæ¶é´,åä½ç§ |
| | | */ |
| | | int time() default 60; |
| | | |
| | | /** |
| | | * éæµæ¬¡æ° |
| | | */ |
| | | int count() default 100; |
| | | |
| | | /** |
| | | * éæµç±»å |
| | | */ |
| | | LimitType limitType() default LimitType.DEFAULT; |
| | | |
| | | /** |
| | | * æç¤ºæ¶æ¯ æ¯æå½é
å æ ¼å¼ä¸º {code} |
| | | */ |
| | | String message() default "{rate.limiter.message}"; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.ratelimiter.aspectj; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.MessageUtils; |
| | | import org.dromara.common.core.utils.ServletUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.ratelimiter.annotation.RateLimiter; |
| | | import org.dromara.common.ratelimiter.enums.LimitType; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.aspectj.lang.JoinPoint; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Before; |
| | | import org.aspectj.lang.reflect.MethodSignature; |
| | | import org.redisson.api.RateType; |
| | | import org.springframework.core.DefaultParameterNameDiscoverer; |
| | | import org.springframework.core.ParameterNameDiscoverer; |
| | | import org.springframework.expression.EvaluationContext; |
| | | import org.springframework.expression.ExpressionParser; |
| | | import org.springframework.expression.ParserContext; |
| | | import org.springframework.expression.common.TemplateParserContext; |
| | | import org.springframework.expression.spel.standard.SpelExpressionParser; |
| | | import org.springframework.expression.spel.support.StandardEvaluationContext; |
| | | |
| | | import java.lang.reflect.Method; |
| | | |
| | | /** |
| | | * éæµå¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @Aspect |
| | | public class RateLimiterAspect { |
| | | |
| | | /** |
| | | * å®ä¹spel表达å¼è§£æå¨ |
| | | */ |
| | | private final ExpressionParser parser = new SpelExpressionParser(); |
| | | /** |
| | | * å®ä¹spelè§£ææ¨¡ç |
| | | */ |
| | | private final ParserContext parserContext = new TemplateParserContext(); |
| | | /** |
| | | * å®ä¹spelä¸ä¸æå¯¹è±¡è¿è¡è§£æ |
| | | */ |
| | | private final EvaluationContext context = new StandardEvaluationContext(); |
| | | /** |
| | | * æ¹æ³åæ°è§£æå¨ |
| | | */ |
| | | private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); |
| | | |
| | | @Before("@annotation(rateLimiter)") |
| | | public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable { |
| | | int time = rateLimiter.time(); |
| | | int count = rateLimiter.count(); |
| | | String combineKey = getCombineKey(rateLimiter, point); |
| | | try { |
| | | RateType rateType = RateType.OVERALL; |
| | | if (rateLimiter.limitType() == LimitType.CLUSTER) { |
| | | rateType = RateType.PER_CLIENT; |
| | | } |
| | | long number = RedisUtils.rateLimiter(combineKey, rateType, count, time); |
| | | if (number == -1) { |
| | | String message = rateLimiter.message(); |
| | | if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { |
| | | message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); |
| | | } |
| | | throw new ServiceException(message); |
| | | } |
| | | log.info("éå¶ä»¤ç => {}, å©ä½ä»¤ç => {}, ç¼åkey => '{}'", count, number, combineKey); |
| | | } catch (Exception e) { |
| | | if (e instanceof ServiceException) { |
| | | throw e; |
| | | } else { |
| | | throw new RuntimeException("æå¡å¨éæµå¼å¸¸ï¼è¯·ç¨ååè¯"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { |
| | | String key = rateLimiter.key(); |
| | | // è·åæ¹æ³(éè¿æ¹æ³ç¾åæ¥è·å) |
| | | MethodSignature signature = (MethodSignature) point.getSignature(); |
| | | Method method = signature.getMethod(); |
| | | Class<?> targetClass = method.getDeclaringClass(); |
| | | // 夿æ¯å¦æ¯spelæ ¼å¼ |
| | | if (StringUtils.containsAny(key, "#")) { |
| | | // è·ååæ°å¼ |
| | | Object[] args = point.getArgs(); |
| | | // è·åæ¹æ³ä¸åæ°çåç§° |
| | | String[] parameterNames = pnd.getParameterNames(method); |
| | | if (ArrayUtil.isEmpty(parameterNames)) { |
| | | throw new ServiceException("éæµkeyè§£æå¼å¸¸!请è系管çå!"); |
| | | } |
| | | for (int i = 0; i < parameterNames.length; i++) { |
| | | context.setVariable(parameterNames[i], args[i]); |
| | | } |
| | | // è§£æè¿åç»key |
| | | try { |
| | | key = parser.parseExpression(key, parserContext).getValue(context, String.class) + ":"; |
| | | } catch (Exception e) { |
| | | throw new ServiceException("éæµkeyè§£æå¼å¸¸!请è系管çå!"); |
| | | } |
| | | } |
| | | StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY); |
| | | stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":"); |
| | | if (rateLimiter.limitType() == LimitType.IP) { |
| | | // è·å请æ±ip |
| | | stringBuffer.append(ServletUtils.getClientIP()).append(":"); |
| | | } else if (rateLimiter.limitType() == LimitType.CLUSTER) { |
| | | // è·å客æ·ç«¯å®ä¾id |
| | | stringBuffer.append(RedisUtils.getClient().getId()).append(":"); |
| | | } |
| | | return stringBuffer.append(key).toString(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.ratelimiter.config; |
| | | |
| | | import org.dromara.common.ratelimiter.aspectj.RateLimiterAspect; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.data.redis.connection.RedisConfiguration; |
| | | |
| | | /** |
| | | * @author guangxin |
| | | * @date 2023/1/18 |
| | | */ |
| | | @AutoConfiguration(after = RedisConfiguration.class) |
| | | public class RateLimiterConfig { |
| | | |
| | | @Bean |
| | | public RateLimiterAspect rateLimiterAspect() { |
| | | return new RateLimiterAspect(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.ratelimiter.enums; |
| | | |
| | | /** |
| | | * éæµç±»å |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | |
| | | public enum LimitType { |
| | | /** |
| | | * é»è®¤çç¥å
¨å±éæµ |
| | | */ |
| | | DEFAULT, |
| | | |
| | | /** |
| | | * æ ¹æ®è¯·æ±è
IPè¿è¡éæµ |
| | | */ |
| | | IP, |
| | | |
| | | /** |
| | | * å®ä¾éæµ(é群å¤å端å®ä¾) |
| | | */ |
| | | CLUSTER |
| | | } |
| | |
| | | com.ruoyi.common.ratelimiter.config.RateLimiterConfig |
| | | org.dromara.common.ratelimiter.config.RateLimiterConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | <dependencies> |
| | | <!-- RuoYi Common Core--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.config; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.dromara.common.redis.config.properties.RedissonProperties; |
| | | import org.dromara.common.redis.handler.KeyPrefixHandler; |
| | | import org.dromara.common.redis.manager.PlusSpringCacheManager; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.redisson.codec.JsonJacksonCodec; |
| | | import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.cache.CacheManager; |
| | | import org.springframework.cache.annotation.EnableCaching; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | /** |
| | | * redisé
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @AutoConfiguration |
| | | @EnableCaching |
| | | @EnableConfigurationProperties(RedissonProperties.class) |
| | | public class RedisConfig { |
| | | |
| | | @Autowired |
| | | private RedissonProperties redissonProperties; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Bean |
| | | public RedissonAutoConfigurationCustomizer redissonCustomizer() { |
| | | return config -> { |
| | | config.setThreads(redissonProperties.getThreads()) |
| | | .setNettyThreads(redissonProperties.getNettyThreads()) |
| | | .setCodec(new JsonJacksonCodec(objectMapper)); |
| | | RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); |
| | | if (ObjectUtil.isNotNull(singleServerConfig)) { |
| | | // 使ç¨åæºæ¨¡å¼ |
| | | config.useSingleServer() |
| | | //设置redis keyåç¼ |
| | | .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) |
| | | .setTimeout(singleServerConfig.getTimeout()) |
| | | .setClientName(singleServerConfig.getClientName()) |
| | | .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) |
| | | .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) |
| | | .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) |
| | | .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); |
| | | } |
| | | // é群é
ç½®æ¹å¼ åè䏿¹æ³¨é |
| | | RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); |
| | | if (ObjectUtil.isNotNull(clusterServersConfig)) { |
| | | config.useClusterServers() |
| | | //设置redis keyåç¼ |
| | | .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) |
| | | .setTimeout(clusterServersConfig.getTimeout()) |
| | | .setClientName(clusterServersConfig.getClientName()) |
| | | .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) |
| | | .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) |
| | | .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) |
| | | .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) |
| | | .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) |
| | | .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) |
| | | .setReadMode(clusterServersConfig.getReadMode()) |
| | | .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); |
| | | } |
| | | log.info("åå§å redis é
ç½®"); |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹ç¼å管çå¨ æ´åspring-cache |
| | | */ |
| | | @Bean |
| | | public CacheManager cacheManager() { |
| | | return new PlusSpringCacheManager(); |
| | | } |
| | | |
| | | /** |
| | | * redisé群é
ç½® yml |
| | | * |
| | | * --- # redis é群é
ç½®(åæºä¸é群åªè½å¼å¯ä¸ä¸ªå¦ä¸ä¸ªéè¦æ³¨éæ) |
| | | * spring: |
| | | * redis: |
| | | * cluster: |
| | | * nodes: |
| | | * - 192.168.0.100:6379 |
| | | * - 192.168.0.101:6379 |
| | | * - 192.168.0.102:6379 |
| | | * # å¯ç |
| | | * password: |
| | | * # è¿æ¥è¶
æ¶æ¶é´ |
| | | * timeout: 10s |
| | | * # æ¯å¦å¼å¯ssl |
| | | * ssl: false |
| | | * |
| | | * redisson: |
| | | * # çº¿ç¨æ± æ°é |
| | | * threads: 16 |
| | | * # Nettyçº¿ç¨æ± æ°é |
| | | * nettyThreads: 32 |
| | | * # é群é
ç½® |
| | | * clusterServersConfig: |
| | | * # 客æ·ç«¯åç§° |
| | | * clientName: ${ruoyi.name} |
| | | * # masteræå°ç©ºé²è¿æ¥æ° |
| | | * masterConnectionMinimumIdleSize: 32 |
| | | * # masterè¿æ¥æ± å¤§å° |
| | | * masterConnectionPoolSize: 64 |
| | | * # slaveæå°ç©ºé²è¿æ¥æ° |
| | | * slaveConnectionMinimumIdleSize: 32 |
| | | * # slaveè¿æ¥æ± å¤§å° |
| | | * slaveConnectionPoolSize: 64 |
| | | * # è¿æ¥ç©ºé²è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | * idleConnectionTimeout: 10000 |
| | | * # å½ä»¤çå¾
è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | * timeout: 3000 |
| | | * # åå¸å订é
è¿æ¥æ± å¤§å° |
| | | * subscriptionConnectionPoolSize: 50 |
| | | * # è¯»åæ¨¡å¼ |
| | | * readMode: "SLAVE" |
| | | * # 订é
æ¨¡å¼ |
| | | * subscriptionMode: "MASTER" |
| | | */ |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | import org.redisson.config.ReadMode; |
| | | import org.redisson.config.SubscriptionMode; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * Redisson é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "redisson") |
| | | public class RedissonProperties { |
| | | |
| | | /** |
| | | * redisç¼åkeyåç¼ |
| | | */ |
| | | private String keyPrefix; |
| | | |
| | | /** |
| | | * çº¿ç¨æ± æ°é,é»è®¤å¼ = å½åå¤çæ ¸æ°é * 2 |
| | | */ |
| | | private int threads; |
| | | |
| | | /** |
| | | * Nettyçº¿ç¨æ± æ°é,é»è®¤å¼ = å½åå¤çæ ¸æ°é * 2 |
| | | */ |
| | | private int nettyThreads; |
| | | |
| | | /** |
| | | * åæºæå¡é
ç½® |
| | | */ |
| | | private SingleServerConfig singleServerConfig; |
| | | |
| | | /** |
| | | * é群æå¡é
ç½® |
| | | */ |
| | | private ClusterServersConfig clusterServersConfig; |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public static class SingleServerConfig { |
| | | |
| | | /** |
| | | * 客æ·ç«¯åç§° |
| | | */ |
| | | private String clientName; |
| | | |
| | | /** |
| | | * æå°ç©ºé²è¿æ¥æ° |
| | | */ |
| | | private int connectionMinimumIdleSize; |
| | | |
| | | /** |
| | | * è¿æ¥æ± å¤§å° |
| | | */ |
| | | private int connectionPoolSize; |
| | | |
| | | /** |
| | | * è¿æ¥ç©ºé²è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | */ |
| | | private int idleConnectionTimeout; |
| | | |
| | | /** |
| | | * å½ä»¤çå¾
è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | */ |
| | | private int timeout; |
| | | |
| | | /** |
| | | * åå¸å订é
è¿æ¥æ± å¤§å° |
| | | */ |
| | | private int subscriptionConnectionPoolSize; |
| | | |
| | | } |
| | | |
| | | @Data |
| | | @NoArgsConstructor |
| | | public static class ClusterServersConfig { |
| | | |
| | | /** |
| | | * 客æ·ç«¯åç§° |
| | | */ |
| | | private String clientName; |
| | | |
| | | /** |
| | | * masteræå°ç©ºé²è¿æ¥æ° |
| | | */ |
| | | private int masterConnectionMinimumIdleSize; |
| | | |
| | | /** |
| | | * masterè¿æ¥æ± å¤§å° |
| | | */ |
| | | private int masterConnectionPoolSize; |
| | | |
| | | /** |
| | | * slaveæå°ç©ºé²è¿æ¥æ° |
| | | */ |
| | | private int slaveConnectionMinimumIdleSize; |
| | | |
| | | /** |
| | | * slaveè¿æ¥æ± å¤§å° |
| | | */ |
| | | private int slaveConnectionPoolSize; |
| | | |
| | | /** |
| | | * è¿æ¥ç©ºé²è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | */ |
| | | private int idleConnectionTimeout; |
| | | |
| | | /** |
| | | * å½ä»¤çå¾
è¶
æ¶ï¼åä½ï¼æ¯«ç§ |
| | | */ |
| | | private int timeout; |
| | | |
| | | /** |
| | | * åå¸å订é
è¿æ¥æ± å¤§å° |
| | | */ |
| | | private int subscriptionConnectionPoolSize; |
| | | |
| | | /** |
| | | * è¯»åæ¨¡å¼ |
| | | */ |
| | | private ReadMode readMode; |
| | | |
| | | /** |
| | | * 订é
æ¨¡å¼ |
| | | */ |
| | | private SubscriptionMode subscriptionMode; |
| | | |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.handler; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.redisson.api.NameMapper; |
| | | |
| | | /** |
| | | * redisç¼åkeyåç¼å¤ç |
| | | * |
| | | * @author ye |
| | | * @date 2022/7/14 17:44 |
| | | * @since 4.3.0 |
| | | */ |
| | | public class KeyPrefixHandler implements NameMapper { |
| | | |
| | | private final String keyPrefix; |
| | | |
| | | public KeyPrefixHandler(String keyPrefix) { |
| | | //åç¼ä¸ºç©º åè¿å空åç¼ |
| | | this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":"; |
| | | } |
| | | |
| | | /** |
| | | * å¢å åç¼ |
| | | */ |
| | | @Override |
| | | public String map(String name) { |
| | | if (StringUtils.isBlank(name)) { |
| | | return null; |
| | | } |
| | | if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { |
| | | return keyPrefix + name; |
| | | } |
| | | return name; |
| | | } |
| | | |
| | | /** |
| | | * å»é¤åç¼ |
| | | */ |
| | | @Override |
| | | public String unmap(String name) { |
| | | if (StringUtils.isBlank(name)) { |
| | | return null; |
| | | } |
| | | if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { |
| | | return name.substring(keyPrefix.length()); |
| | | } |
| | | return name; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | /** |
| | | * Copyright (c) 2013-2021 Nikita Koksharov |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package org.dromara.common.redis.manager; |
| | | |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.redisson.api.RMap; |
| | | import org.redisson.api.RMapCache; |
| | | import org.redisson.spring.cache.CacheConfig; |
| | | import org.redisson.spring.cache.RedissonCache; |
| | | import org.springframework.boot.convert.DurationStyle; |
| | | import org.springframework.cache.Cache; |
| | | import org.springframework.cache.CacheManager; |
| | | import org.springframework.cache.transaction.TransactionAwareCacheDecorator; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.ConcurrentMap; |
| | | |
| | | /** |
| | | * A {@link org.springframework.cache.CacheManager} implementation |
| | | * backed by Redisson instance. |
| | | * <p> |
| | | * ä¿®æ¹ RedissonSpringCacheManager æºç |
| | | * éå cacheName å¤çæ¹æ³ æ¯æå¤åæ° |
| | | * |
| | | * @author Nikita Koksharov |
| | | * |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public class PlusSpringCacheManager implements CacheManager { |
| | | |
| | | private boolean dynamic = true; |
| | | |
| | | private boolean allowNullValues = true; |
| | | |
| | | private boolean transactionAware = true; |
| | | |
| | | Map<String, CacheConfig> configMap = new ConcurrentHashMap<>(); |
| | | ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * Creates CacheManager supplied by Redisson instance |
| | | */ |
| | | public PlusSpringCacheManager() { |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Defines possibility of storing {@code null} values. |
| | | * <p> |
| | | * Default is <code>true</code> |
| | | * |
| | | * @param allowNullValues stores if <code>true</code> |
| | | */ |
| | | public void setAllowNullValues(boolean allowNullValues) { |
| | | this.allowNullValues = allowNullValues; |
| | | } |
| | | |
| | | /** |
| | | * Defines if cache aware of Spring-managed transactions. |
| | | * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase. |
| | | * <p> |
| | | * Default is <code>false</code> |
| | | * |
| | | * @param transactionAware cache is transaction aware if <code>true</code> |
| | | */ |
| | | public void setTransactionAware(boolean transactionAware) { |
| | | this.transactionAware = transactionAware; |
| | | } |
| | | |
| | | /** |
| | | * Defines 'fixed' cache names. |
| | | * A new cache instance will not be created in dynamic for non-defined names. |
| | | * <p> |
| | | * `null` parameter setups dynamic mode |
| | | * |
| | | * @param names of caches |
| | | */ |
| | | public void setCacheNames(Collection<String> names) { |
| | | if (names != null) { |
| | | for (String name : names) { |
| | | getCache(name); |
| | | } |
| | | dynamic = false; |
| | | } else { |
| | | dynamic = true; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Set cache config mapped by cache name |
| | | * |
| | | * @param config object |
| | | */ |
| | | public void setConfig(Map<String, ? extends CacheConfig> config) { |
| | | this.configMap = (Map<String, CacheConfig>) config; |
| | | } |
| | | |
| | | protected CacheConfig createDefaultConfig() { |
| | | return new CacheConfig(); |
| | | } |
| | | |
| | | @Override |
| | | public Cache getCache(String name) { |
| | | Cache cache = instanceMap.get(name); |
| | | if (cache != null) { |
| | | return cache; |
| | | } |
| | | if (!dynamic) { |
| | | return cache; |
| | | } |
| | | |
| | | CacheConfig config = configMap.get(name); |
| | | if (config == null) { |
| | | config = createDefaultConfig(); |
| | | configMap.put(name, config); |
| | | } |
| | | |
| | | // éå cacheName æ¯æå¤åæ° |
| | | String[] array = StringUtils.delimitedListToStringArray(name, "#"); |
| | | name = array[0]; |
| | | if (array.length > 1) { |
| | | config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis()); |
| | | } |
| | | if (array.length > 2) { |
| | | config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis()); |
| | | } |
| | | if (array.length > 3) { |
| | | config.setMaxSize(Integer.parseInt(array[3])); |
| | | } |
| | | |
| | | if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) { |
| | | return createMap(name, config); |
| | | } |
| | | |
| | | return createMapCache(name, config); |
| | | } |
| | | |
| | | private Cache createMap(String name, CacheConfig config) { |
| | | RMap<Object, Object> map = RedisUtils.getClient().getMap(name); |
| | | |
| | | Cache cache = new RedissonCache(map, allowNullValues); |
| | | if (transactionAware) { |
| | | cache = new TransactionAwareCacheDecorator(cache); |
| | | } |
| | | Cache oldCache = instanceMap.putIfAbsent(name, cache); |
| | | if (oldCache != null) { |
| | | cache = oldCache; |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | private Cache createMapCache(String name, CacheConfig config) { |
| | | RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name); |
| | | |
| | | Cache cache = new RedissonCache(map, config, allowNullValues); |
| | | if (transactionAware) { |
| | | cache = new TransactionAwareCacheDecorator(cache); |
| | | } |
| | | Cache oldCache = instanceMap.putIfAbsent(name, cache); |
| | | if (oldCache != null) { |
| | | cache = oldCache; |
| | | } else { |
| | | map.setMaxSize(config.getMaxSize()); |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | @Override |
| | | public Collection<String> getCacheNames() { |
| | | return Collections.unmodifiableSet(configMap.keySet()); |
| | | } |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.utils; |
| | | |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.redisson.api.RMap; |
| | | import org.springframework.cache.Cache; |
| | | import org.springframework.cache.CacheManager; |
| | | |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * ç¼åæä½å·¥å
·ç±» {@link } |
| | | * |
| | | * @author Michelle.Chung |
| | | * @date 2022/8/13 |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | @SuppressWarnings(value = {"unchecked"}) |
| | | public class CacheUtils { |
| | | |
| | | private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class); |
| | | |
| | | /** |
| | | * è·åç¼åç»å
ææçKEY |
| | | * |
| | | * @param cacheNames ç¼åç»åç§° |
| | | */ |
| | | public static Set<Object> keys(String cacheNames) { |
| | | RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache(); |
| | | return rmap.keySet(); |
| | | } |
| | | |
| | | /** |
| | | * è·åç¼åå¼ |
| | | * |
| | | * @param cacheNames ç¼åç»åç§° |
| | | * @param key ç¼åkey |
| | | */ |
| | | public static <T> T get(String cacheNames, Object key) { |
| | | Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key); |
| | | return wrapper != null ? (T) wrapper.get() : null; |
| | | } |
| | | |
| | | /** |
| | | * ä¿åç¼åå¼ |
| | | * |
| | | * @param cacheNames ç¼åç»åç§° |
| | | * @param key ç¼åkey |
| | | * @param value ç¼åå¼ |
| | | */ |
| | | public static void put(String cacheNames, Object key, Object value) { |
| | | CACHE_MANAGER.getCache(cacheNames).put(key, value); |
| | | } |
| | | |
| | | /** |
| | | * å é¤ç¼åå¼ |
| | | * |
| | | * @param cacheNames ç¼åç»åç§° |
| | | * @param key ç¼åkey |
| | | */ |
| | | public static void evict(String cacheNames, Object key) { |
| | | CACHE_MANAGER.getCache(cacheNames).evict(key); |
| | | } |
| | | |
| | | /** |
| | | * æ¸
空ç¼åå¼ |
| | | * |
| | | * @param cacheNames ç¼åç»åç§° |
| | | */ |
| | | public static void clear(String cacheNames) { |
| | | CACHE_MANAGER.getCache(cacheNames).clear(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.utils; |
| | | |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.redisson.api.*; |
| | | |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.function.Consumer; |
| | | |
| | | /** |
| | | * åå¸å¼éåå·¥å
· |
| | | * è½»é级éå ééçº§æ°æ®é è¯·ä½¿ç¨ MQ |
| | | * è¦æ± redis 5.X ä»¥ä¸ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 æ°å¢ |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class QueueUtils { |
| | | |
| | | private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); |
| | | |
| | | |
| | | /** |
| | | * è·å客æ·ç«¯å®ä¾ |
| | | */ |
| | | public static RedissonClient getClient() { |
| | | return CLIENT; |
| | | } |
| | | |
| | | /** |
| | | * æ·»å æ®ééåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param data æ°æ® |
| | | */ |
| | | public static <T> boolean addQueueObject(String queueName, T data) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | return queue.offer(data); |
| | | } |
| | | |
| | | /** |
| | | * éç¨è·åä¸ä¸ªéåæ°æ® æ²¡ææ°æ®è¿å null(䏿¯æå»¶è¿éå) |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | public static <T> T getQueueObject(String queueName) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | return queue.poll(); |
| | | } |
| | | |
| | | /** |
| | | * éç¨å é¤éåæ°æ®(䏿¯æå»¶è¿éå) |
| | | */ |
| | | public static <T> boolean removeQueueObject(String queueName, T data) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | return queue.remove(data); |
| | | } |
| | | |
| | | /** |
| | | * éç¨éæ¯éå ææé»å¡çå¬ æ¥é(䏿¯æå»¶è¿éå) |
| | | */ |
| | | public static <T> boolean destroyQueue(String queueName) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | return queue.delete(); |
| | | } |
| | | |
| | | /** |
| | | * æ·»å å»¶è¿éåæ°æ® é»è®¤æ¯«ç§ |
| | | * |
| | | * @param queueName éåå |
| | | * @param data æ°æ® |
| | | * @param time å»¶è¿æ¶é´ |
| | | */ |
| | | public static <T> void addDelayedQueueObject(String queueName, T data, long time) { |
| | | addDelayedQueueObject(queueName, data, time, TimeUnit.MILLISECONDS); |
| | | } |
| | | |
| | | /** |
| | | * æ·»å å»¶è¿éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param data æ°æ® |
| | | * @param time å»¶è¿æ¶é´ |
| | | * @param timeUnit åä½ |
| | | */ |
| | | public static <T> void addDelayedQueueObject(String queueName, T data, long time, TimeUnit timeUnit) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue); |
| | | delayedQueue.offer(data, time, timeUnit); |
| | | } |
| | | |
| | | /** |
| | | * è·åä¸ä¸ªå»¶è¿éåæ°æ® æ²¡ææ°æ®è¿å null |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | public static <T> T getDelayedQueueObject(String queueName) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue); |
| | | return delayedQueue.poll(); |
| | | } |
| | | |
| | | /** |
| | | * å é¤å»¶è¿éåæ°æ® |
| | | */ |
| | | public static <T> boolean removeDelayedQueueObject(String queueName, T data) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue); |
| | | return delayedQueue.remove(data); |
| | | } |
| | | |
| | | /** |
| | | * 鿝延è¿éå ææé»å¡çå¬ æ¥é |
| | | */ |
| | | public static <T> void destroyDelayedQueue(String queueName) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue); |
| | | delayedQueue.destroy(); |
| | | } |
| | | |
| | | /** |
| | | * æ·»å ä¼å
éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param data æ°æ® |
| | | */ |
| | | public static <T> boolean addPriorityQueueObject(String queueName, T data) { |
| | | RPriorityBlockingQueue<T> priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName); |
| | | return priorityBlockingQueue.offer(data); |
| | | } |
| | | |
| | | /** |
| | | * å°è¯è®¾ç½® æçéå 容é ç¨äºéå¶æ°é |
| | | * |
| | | * @param queueName éåå |
| | | * @param capacity 容é |
| | | */ |
| | | public static <T> boolean trySetBoundedQueueCapacity(String queueName, int capacity) { |
| | | RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); |
| | | return boundedBlockingQueue.trySetCapacity(capacity); |
| | | } |
| | | |
| | | /** |
| | | * å°è¯è®¾ç½® æçéå 容é ç¨äºéå¶æ°é |
| | | * |
| | | * @param queueName éåå |
| | | * @param capacity 容é |
| | | * @param destroy å·²å卿¯å¦éæ¯ |
| | | */ |
| | | public static <T> boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) { |
| | | RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); |
| | | if (boundedBlockingQueue.isExists() && destroy) { |
| | | destroyQueue(queueName); |
| | | } |
| | | return boundedBlockingQueue.trySetCapacity(capacity); |
| | | } |
| | | |
| | | /** |
| | | * æ·»å æçéåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param data æ°æ® |
| | | * @return æ·»å æå true 已达å°çé false |
| | | */ |
| | | public static <T> boolean addBoundedQueueObject(String queueName, T data) { |
| | | RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); |
| | | return boundedBlockingQueue.offer(data); |
| | | } |
| | | |
| | | /** |
| | | * 订é
é»å¡éå(å¯è®¢é
ææå®ç°ç±» ä¾å¦: å»¶è¿ ä¼å
æç ç) |
| | | */ |
| | | public static <T> void subscribeBlockingQueue(String queueName, Consumer<T> consumer) { |
| | | RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); |
| | | queue.subscribeOnElements(consumer); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.redis.utils; |
| | | |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.redisson.api.*; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.function.Consumer; |
| | | import java.util.stream.Collectors; |
| | | import java.util.stream.Stream; |
| | | |
| | | /** |
| | | * redis å·¥å
·ç±» |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.1.0 æ°å¢ |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | @SuppressWarnings(value = {"unchecked", "rawtypes"}) |
| | | public class RedisUtils { |
| | | |
| | | private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); |
| | | |
| | | /** |
| | | * éæµ |
| | | * |
| | | * @param key éæµkey |
| | | * @param rateType éæµç±»å |
| | | * @param rate éç |
| | | * @param rateInterval éçé´é |
| | | * @return -1 表示失败 |
| | | */ |
| | | public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) { |
| | | RRateLimiter rateLimiter = CLIENT.getRateLimiter(key); |
| | | rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS); |
| | | if (rateLimiter.tryAcquire()) { |
| | | return rateLimiter.availablePermits(); |
| | | } else { |
| | | return -1L; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·å客æ·ç«¯å®ä¾ |
| | | */ |
| | | public static RedissonClient getClient() { |
| | | return CLIENT; |
| | | } |
| | | |
| | | /** |
| | | * åå¸ééæ¶æ¯ |
| | | * |
| | | * @param channelKey éékey |
| | | * @param msg åéæ°æ® |
| | | * @param consumer èªå®ä¹å¤ç |
| | | */ |
| | | public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) { |
| | | RTopic topic = CLIENT.getTopic(channelKey); |
| | | topic.publish(msg); |
| | | consumer.accept(msg); |
| | | } |
| | | |
| | | public static <T> void publish(String channelKey, T msg) { |
| | | RTopic topic = CLIENT.getTopic(channelKey); |
| | | topic.publish(msg); |
| | | } |
| | | |
| | | /** |
| | | * 订é
ééæ¥æ¶æ¶æ¯ |
| | | * |
| | | * @param channelKey éékey |
| | | * @param clazz æ¶æ¯ç±»å |
| | | * @param consumer èªå®ä¹å¤ç |
| | | */ |
| | | public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) { |
| | | RTopic topic = CLIENT.getTopic(channelKey); |
| | | topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); |
| | | } |
| | | |
| | | /** |
| | | * ç¼ååºæ¬ç对象ï¼IntegerãStringãå®ä½ç±»ç |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param value ç¼åçå¼ |
| | | */ |
| | | public static <T> void setCacheObject(final String key, final T value) { |
| | | setCacheObject(key, value, false); |
| | | } |
| | | |
| | | /** |
| | | * ç¼ååºæ¬ç对象ï¼ä¿çå½å对象 TTL æææ |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param value ç¼åçå¼ |
| | | * @param isSaveTtl æ¯å¦ä¿çTTLæææ(ä¾å¦: setä¹åttlå©ä½90 setä¹åè¿æ¯ä¸º90) |
| | | * @since Redis 6.X 以ä¸ä½¿ç¨ setAndKeepTTL å
¼å®¹ 5.X æ¹æ¡ |
| | | */ |
| | | public static <T> void setCacheObject(final String key, final T value, final boolean isSaveTtl) { |
| | | RBucket<T> bucket = CLIENT.getBucket(key); |
| | | if (isSaveTtl) { |
| | | try { |
| | | bucket.setAndKeepTTL(value); |
| | | } catch (Exception e) { |
| | | long timeToLive = bucket.remainTimeToLive(); |
| | | setCacheObject(key, value, Duration.ofMillis(timeToLive)); |
| | | } |
| | | } else { |
| | | bucket.set(value); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ç¼ååºæ¬ç对象ï¼IntegerãStringãå®ä½ç±»ç |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param value ç¼åçå¼ |
| | | * @param duration æ¶é´ |
| | | */ |
| | | public static <T> void setCacheObject(final String key, final T value, final Duration duration) { |
| | | RBatch batch = CLIENT.createBatch(); |
| | | RBucketAsync<T> bucket = batch.getBucket(key); |
| | | bucket.setAsync(value); |
| | | bucket.expireAsync(duration); |
| | | batch.execute(); |
| | | } |
| | | |
| | | /** |
| | | * 注å对象çå¬å¨ |
| | | * <p> |
| | | * key çå¬å¨éå¼å¯ `notify-keyspace-events` ç redis ç¸å
³é
ç½® |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param listener çå¬å¨é
ç½® |
| | | */ |
| | | public static <T> void addObjectListener(final String key, final ObjectListener listener) { |
| | | RBucket<T> result = CLIENT.getBucket(key); |
| | | result.addListener(listener); |
| | | } |
| | | |
| | | /** |
| | | * è®¾ç½®æææ¶é´ |
| | | * |
| | | * @param key Redisé® |
| | | * @param timeout è¶
æ¶æ¶é´ |
| | | * @return true=设置æåï¼false=设置失败 |
| | | */ |
| | | public static boolean expire(final String key, final long timeout) { |
| | | return expire(key, Duration.ofSeconds(timeout)); |
| | | } |
| | | |
| | | /** |
| | | * è®¾ç½®æææ¶é´ |
| | | * |
| | | * @param key Redisé® |
| | | * @param duration è¶
æ¶æ¶é´ |
| | | * @return true=设置æåï¼false=设置失败 |
| | | */ |
| | | public static boolean expire(final String key, final Duration duration) { |
| | | RBucket rBucket = CLIENT.getBucket(key); |
| | | return rBucket.expire(duration); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åçåºæ¬å¯¹è±¡ã |
| | | * |
| | | * @param key ç¼åé®å¼ |
| | | * @return ç¼åé®å¼å¯¹åºçæ°æ® |
| | | */ |
| | | public static <T> T getCacheObject(final String key) { |
| | | RBucket<T> rBucket = CLIENT.getBucket(key); |
| | | return rBucket.get(); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾keyå©ä½åæ´»æ¶é´ |
| | | * |
| | | * @param key ç¼åé®å¼ |
| | | * @return å©ä½åæ´»æ¶é´ |
| | | */ |
| | | public static <T> long getTimeToLive(final String key) { |
| | | RBucket<T> rBucket = CLIENT.getBucket(key); |
| | | return rBucket.remainTimeToLive(); |
| | | } |
| | | |
| | | /** |
| | | * å é¤å个对象 |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | */ |
| | | public static boolean deleteObject(final String key) { |
| | | return CLIENT.getBucket(key).delete(); |
| | | } |
| | | |
| | | /** |
| | | * å é¤éå对象 |
| | | * |
| | | * @param collection å¤ä¸ªå¯¹è±¡ |
| | | */ |
| | | public static void deleteObject(final Collection collection) { |
| | | RBatch batch = CLIENT.createBatch(); |
| | | collection.forEach(t -> { |
| | | batch.getBucket(t.toString()).deleteAsync(); |
| | | }); |
| | | batch.execute(); |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥ç¼å对象æ¯å¦åå¨ |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | */ |
| | | public static boolean isExistsObject(final String key) { |
| | | return CLIENT.getBucket(key).isExists(); |
| | | } |
| | | |
| | | /** |
| | | * ç¼åListæ°æ® |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param dataList å¾
ç¼åçListæ°æ® |
| | | * @return ç¼åç对象 |
| | | */ |
| | | public static <T> boolean setCacheList(final String key, final List<T> dataList) { |
| | | RList<T> rList = CLIENT.getList(key); |
| | | return rList.addAll(dataList); |
| | | } |
| | | |
| | | /** |
| | | * 注åListçå¬å¨ |
| | | * <p> |
| | | * key çå¬å¨éå¼å¯ `notify-keyspace-events` ç redis ç¸å
³é
ç½® |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param listener çå¬å¨é
ç½® |
| | | */ |
| | | public static <T> void addListListener(final String key, final ObjectListener listener) { |
| | | RList<T> rList = CLIENT.getList(key); |
| | | rList.addListener(listener); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åçlist对象 |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @return ç¼åé®å¼å¯¹åºçæ°æ® |
| | | */ |
| | | public static <T> List<T> getCacheList(final String key) { |
| | | RList<T> rList = CLIENT.getList(key); |
| | | return rList.readAll(); |
| | | } |
| | | |
| | | /** |
| | | * ç¼åSet |
| | | * |
| | | * @param key ç¼åé®å¼ |
| | | * @param dataSet ç¼åçæ°æ® |
| | | * @return ç¼åæ°æ®ç对象 |
| | | */ |
| | | public static <T> boolean setCacheSet(final String key, final Set<T> dataSet) { |
| | | RSet<T> rSet = CLIENT.getSet(key); |
| | | return rSet.addAll(dataSet); |
| | | } |
| | | |
| | | /** |
| | | * 注åSetçå¬å¨ |
| | | * <p> |
| | | * key çå¬å¨éå¼å¯ `notify-keyspace-events` ç redis ç¸å
³é
ç½® |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param listener çå¬å¨é
ç½® |
| | | */ |
| | | public static <T> void addSetListener(final String key, final ObjectListener listener) { |
| | | RSet<T> rSet = CLIENT.getSet(key); |
| | | rSet.addListener(listener); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åçset |
| | | * |
| | | * @param key ç¼åçkey |
| | | * @return set对象 |
| | | */ |
| | | public static <T> Set<T> getCacheSet(final String key) { |
| | | RSet<T> rSet = CLIENT.getSet(key); |
| | | return rSet.readAll(); |
| | | } |
| | | |
| | | /** |
| | | * ç¼åMap |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param dataMap ç¼åçæ°æ® |
| | | */ |
| | | public static <T> void setCacheMap(final String key, final Map<String, T> dataMap) { |
| | | if (dataMap != null) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | rMap.putAll(dataMap); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 注åMapçå¬å¨ |
| | | * <p> |
| | | * key çå¬å¨éå¼å¯ `notify-keyspace-events` ç redis ç¸å
³é
ç½® |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @param listener çå¬å¨é
ç½® |
| | | */ |
| | | public static <T> void addMapListener(final String key, final ObjectListener listener) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | rMap.addListener(listener); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åçMap |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @return map对象 |
| | | */ |
| | | public static <T> Map<String, T> getCacheMap(final String key) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | return rMap.getAll(rMap.keySet()); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åMapçkeyå表 |
| | | * |
| | | * @param key ç¼åçé®å¼ |
| | | * @return keyå表 |
| | | */ |
| | | public static <T> Set<String> getCacheMapKeySet(final String key) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | return rMap.keySet(); |
| | | } |
| | | |
| | | /** |
| | | * å¾Hashä¸åå
¥æ°æ® |
| | | * |
| | | * @param key Redisé® |
| | | * @param hKey Hashé® |
| | | * @param value å¼ |
| | | */ |
| | | public static <T> void setCacheMapValue(final String key, final String hKey, final T value) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | rMap.put(hKey, value); |
| | | } |
| | | |
| | | /** |
| | | * è·åHashä¸çæ°æ® |
| | | * |
| | | * @param key Redisé® |
| | | * @param hKey Hashé® |
| | | * @return Hashä¸ç对象 |
| | | */ |
| | | public static <T> T getCacheMapValue(final String key, final String hKey) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | return rMap.get(hKey); |
| | | } |
| | | |
| | | /** |
| | | * å é¤Hashä¸çæ°æ® |
| | | * |
| | | * @param key Redisé® |
| | | * @param hKey Hashé® |
| | | * @return Hashä¸ç对象 |
| | | */ |
| | | public static <T> T delCacheMapValue(final String key, final String hKey) { |
| | | RMap<String, T> rMap = CLIENT.getMap(key); |
| | | return rMap.remove(hKey); |
| | | } |
| | | |
| | | /** |
| | | * è·åå¤ä¸ªHashä¸çæ°æ® |
| | | * |
| | | * @param key Redisé® |
| | | * @param hKeys Hashé®éå |
| | | * @return Hash对象éå |
| | | */ |
| | | public static <K, V> Map<K, V> getMultiCacheMapValue(final String key, final Set<K> hKeys) { |
| | | RMap<K, V> rMap = CLIENT.getMap(key); |
| | | return rMap.getAll(hKeys); |
| | | } |
| | | |
| | | /** |
| | | * 设置ååå¼ |
| | | * |
| | | * @param key Redisé® |
| | | * @param value å¼ |
| | | */ |
| | | public static void setAtomicValue(String key, long value) { |
| | | RAtomicLong atomic = CLIENT.getAtomicLong(key); |
| | | atomic.set(value); |
| | | } |
| | | |
| | | /** |
| | | * è·åååå¼ |
| | | * |
| | | * @param key Redisé® |
| | | * @return å½åå¼ |
| | | */ |
| | | public static long getAtomicValue(String key) { |
| | | RAtomicLong atomic = CLIENT.getAtomicLong(key); |
| | | return atomic.get(); |
| | | } |
| | | |
| | | /** |
| | | * éå¢ååå¼ |
| | | * |
| | | * @param key Redisé® |
| | | * @return å½åå¼ |
| | | */ |
| | | public static long incrAtomicValue(String key) { |
| | | RAtomicLong atomic = CLIENT.getAtomicLong(key); |
| | | return atomic.incrementAndGet(); |
| | | } |
| | | |
| | | /** |
| | | * éåååå¼ |
| | | * |
| | | * @param key Redisé® |
| | | * @return å½åå¼ |
| | | */ |
| | | public static long decrAtomicValue(String key) { |
| | | RAtomicLong atomic = CLIENT.getAtomicLong(key); |
| | | return atomic.decrementAndGet(); |
| | | } |
| | | |
| | | /** |
| | | * è·å¾ç¼åçåºæ¬å¯¹è±¡å表 |
| | | * |
| | | * @param pattern å符串åç¼ |
| | | * @return 对象å表 |
| | | */ |
| | | public static Collection<String> keys(final String pattern) { |
| | | Stream<String> stream = CLIENT.getKeys().getKeysStreamByPattern(pattern); |
| | | return stream.collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | | * å é¤ç¼åçåºæ¬å¯¹è±¡å表 |
| | | * |
| | | * @param pattern å符串åç¼ |
| | | */ |
| | | public static void deleteKeys(final String pattern) { |
| | | CLIENT.getKeys().deleteByPattern(pattern); |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥redis䏿¯å¦åå¨key |
| | | * |
| | | * @param key é® |
| | | */ |
| | | public static Boolean hasKey(String key) { |
| | | RKeys rKeys = CLIENT.getKeys(); |
| | | return rKeys.countExists(key) > 0; |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.redis.config.RedisConfig |
| | | org.dromara.common.redis.config.RedisConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | <dependencies> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- RuoYi Common Redis--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.satoken.config; |
| | | |
| | | import cn.dev33.satoken.dao.SaTokenDao; |
| | | import cn.dev33.satoken.jwt.StpLogicJwtForSimple; |
| | | import cn.dev33.satoken.stp.StpInterface; |
| | | import cn.dev33.satoken.stp.StpLogic; |
| | | import org.dromara.common.satoken.core.dao.PlusSaTokenDao; |
| | | import org.dromara.common.satoken.core.service.SaPermissionImpl; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
| | | |
| | | /** |
| | | * sa-token é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | public class SaTokenConfig implements WebMvcConfigurer { |
| | | |
| | | @Bean |
| | | public StpLogic getStpLogicJwt() { |
| | | // Sa-Token æ´å jwt (ç®å模å¼) |
| | | return new StpLogicJwtForSimple(); |
| | | } |
| | | |
| | | /** |
| | | * æéæ¥å£å®ç°(使ç¨bean注å
¥æ¹ä¾¿ç¨æ·æ¿æ¢) |
| | | */ |
| | | @Bean |
| | | public StpInterface stpInterface() { |
| | | return new SaPermissionImpl(); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹daoå±åå¨ |
| | | */ |
| | | @Bean |
| | | public SaTokenDao saTokenDao() { |
| | | return new PlusSaTokenDao(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.satoken.core.dao; |
| | | |
| | | import cn.dev33.satoken.dao.SaTokenDao; |
| | | import cn.dev33.satoken.util.SaFoxUtil; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * Sa-Tokenæä¹
屿¥å£(ä½¿ç¨æ¡æ¶èªå¸¦RedisUtilså®ç° åè®®ç»ä¸) |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class PlusSaTokenDao implements SaTokenDao { |
| | | |
| | | /** |
| | | * è·åValueï¼å¦æ è¿ç©º |
| | | */ |
| | | @Override |
| | | public String get(String key) { |
| | | return RedisUtils.getCacheObject(key); |
| | | } |
| | | |
| | | /** |
| | | * åå
¥Valueï¼å¹¶è®¾å®åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void set(String key, String value, long timeout) { |
| | | if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | // 夿æ¯å¦ä¸ºæ°¸ä¸è¿æ |
| | | if (timeout == NEVER_EXPIRE) { |
| | | RedisUtils.setCacheObject(key, value); |
| | | } else { |
| | | RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ä¿®ä¿®æ¹æå®key-valueé®å¼å¯¹ (è¿ææ¶é´ä¸å) |
| | | */ |
| | | @Override |
| | | public void update(String key, String value) { |
| | | long expire = getTimeout(key); |
| | | // -2 = æ æ¤é® |
| | | if (expire == NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | this.set(key, value, expire); |
| | | } |
| | | |
| | | /** |
| | | * å é¤Value |
| | | */ |
| | | @Override |
| | | public void delete(String key) { |
| | | RedisUtils.deleteObject(key); |
| | | } |
| | | |
| | | /** |
| | | * è·åValueçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public long getTimeout(String key) { |
| | | long timeout = RedisUtils.getTimeToLive(key); |
| | | return timeout < 0 ? timeout : timeout / 1000; |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹Valueçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void updateTimeout(String key, long timeout) { |
| | | // 夿æ¯å¦æ³è¦è®¾ç½®ä¸ºæ°¸ä¹
|
| | | if (timeout == NEVER_EXPIRE) { |
| | | long expire = getTimeout(key); |
| | | if (expire == NEVER_EXPIRE) { |
| | | // 妿å
¶å·²ç»è¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼åä¸ä½ä»»ä½å¤ç |
| | | } else { |
| | | // 妿尿ªè¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼é£ä¹å次set䏿¬¡ |
| | | this.set(key, this.get(key), timeout); |
| | | } |
| | | return; |
| | | } |
| | | RedisUtils.expire(key, Duration.ofSeconds(timeout)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * è·åObjectï¼å¦æ è¿ç©º |
| | | */ |
| | | @Override |
| | | public Object getObject(String key) { |
| | | return RedisUtils.getCacheObject(key); |
| | | } |
| | | |
| | | /** |
| | | * åå
¥Objectï¼å¹¶è®¾å®åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void setObject(String key, Object object, long timeout) { |
| | | if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | // 夿æ¯å¦ä¸ºæ°¸ä¸è¿æ |
| | | if (timeout == NEVER_EXPIRE) { |
| | | RedisUtils.setCacheObject(key, object); |
| | | } else { |
| | | RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ´æ°Object (è¿ææ¶é´ä¸å) |
| | | */ |
| | | @Override |
| | | public void updateObject(String key, Object object) { |
| | | long expire = getObjectTimeout(key); |
| | | // -2 = æ æ¤é® |
| | | if (expire == NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | this.setObject(key, object, expire); |
| | | } |
| | | |
| | | /** |
| | | * å é¤Object |
| | | */ |
| | | @Override |
| | | public void deleteObject(String key) { |
| | | RedisUtils.deleteObject(key); |
| | | } |
| | | |
| | | /** |
| | | * è·åObjectçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public long getObjectTimeout(String key) { |
| | | long timeout = RedisUtils.getTimeToLive(key); |
| | | return timeout < 0 ? timeout : timeout / 1000; |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹Objectçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void updateObjectTimeout(String key, long timeout) { |
| | | // 夿æ¯å¦æ³è¦è®¾ç½®ä¸ºæ°¸ä¹
|
| | | if (timeout == NEVER_EXPIRE) { |
| | | long expire = getObjectTimeout(key); |
| | | if (expire == NEVER_EXPIRE) { |
| | | // 妿å
¶å·²ç»è¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼åä¸ä½ä»»ä½å¤ç |
| | | } else { |
| | | // 妿尿ªè¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼é£ä¹å次set䏿¬¡ |
| | | this.setObject(key, this.getObject(key), timeout); |
| | | } |
| | | return; |
| | | } |
| | | RedisUtils.expire(key, Duration.ofSeconds(timeout)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * æç´¢æ°æ® |
| | | */ |
| | | @Override |
| | | public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) { |
| | | Collection<String> keys = RedisUtils.keys(prefix + "*" + keyword + "*"); |
| | | List<String> list = new ArrayList<>(keys); |
| | | return SaFoxUtil.searchList(list, start, size, sortType); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.satoken.core.service; |
| | | |
| | | import cn.dev33.satoken.stp.StpInterface; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.enums.UserType; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * sa-token æé管çå®ç°ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class SaPermissionImpl implements StpInterface { |
| | | |
| | | /** |
| | | * è·åèåæéå表 |
| | | */ |
| | | @Override |
| | | public List<String> getPermissionList(Object loginId, String loginType) { |
| | | LoginUser loginUser = LoginHelper.getLoginUser(); |
| | | UserType userType = UserType.getUserType(loginUser.getUserType()); |
| | | if (userType == UserType.SYS_USER) { |
| | | return new ArrayList<>(loginUser.getMenuPermission()); |
| | | } else if (userType == UserType.APP_USER) { |
| | | // å
¶ä»ç«¯ èªè¡æ ¹æ®ä¸å¡ç¼å |
| | | } |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | /** |
| | | * è·åè§è²æéå表 |
| | | */ |
| | | @Override |
| | | public List<String> getRoleList(Object loginId, String loginType) { |
| | | LoginUser loginUser = LoginHelper.getLoginUser(); |
| | | UserType userType = UserType.getUserType(loginUser.getUserType()); |
| | | if (userType == UserType.SYS_USER) { |
| | | return new ArrayList<>(loginUser.getRolePermission()); |
| | | } else if (userType == UserType.APP_USER) { |
| | | // å
¶ä»ç«¯ èªè¡æ ¹æ®ä¸å¡ç¼å |
| | | } |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.satoken.listener; |
| | | |
| | | import cn.dev33.satoken.config.SaTokenConfig; |
| | | import cn.dev33.satoken.listener.SaTokenListener; |
| | | import cn.dev33.satoken.stp.SaLoginModel; |
| | | import cn.hutool.http.useragent.UserAgent; |
| | | import cn.hutool.http.useragent.UserAgentUtil; |
| | | import org.dromara.common.core.constant.CacheConstants; |
| | | import org.dromara.common.core.domain.dto.UserOnlineDTO; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.enums.UserType; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import org.dromara.common.core.utils.ip.AddressUtils; |
| | | import org.dromara.common.core.utils.ServletUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.time.Duration; |
| | | |
| | | /** |
| | | * ç¨æ·è¡ä¸º 侦å¬å¨çå®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Component |
| | | @Slf4j |
| | | public class UserActionListener implements SaTokenListener { |
| | | |
| | | private final SaTokenConfig tokenConfig; |
| | | |
| | | /** |
| | | * æ¯æ¬¡ç»å½æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { |
| | | UserType userType = UserType.getUserType(loginId.toString()); |
| | | if (userType == UserType.SYS_USER) { |
| | | UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); |
| | | String ip = ServletUtils.getClientIP(); |
| | | LoginUser user = LoginHelper.getLoginUser(); |
| | | UserOnlineDTO dto = new UserOnlineDTO(); |
| | | dto.setIpaddr(ip); |
| | | dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); |
| | | dto.setBrowser(userAgent.getBrowser().getName()); |
| | | dto.setOs(userAgent.getOs().getName()); |
| | | dto.setLoginTime(System.currentTimeMillis()); |
| | | dto.setTokenId(tokenValue); |
| | | dto.setUserName(user.getUsername()); |
| | | dto.setDeptName(user.getDeptName()); |
| | | if(tokenConfig.getTimeout() == -1) { |
| | | RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); |
| | | } else { |
| | | RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); |
| | | } |
| | | log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); |
| | | } else if (userType == UserType.APP_USER) { |
| | | // app端 èªè¡æ ¹æ®ä¸å¡ç¼å |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡æ³¨éæ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doLogout(String loginType, Object loginId, String tokenValue) { |
| | | RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
| | | log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡è¢«è¸¢ä¸çº¿æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doKickout(String loginType, Object loginId, String tokenValue) { |
| | | RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
| | | log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡è¢«é¡¶ä¸çº¿æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doReplaced(String loginType, Object loginId, String tokenValue) { |
| | | RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
| | | log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡è¢«å°ç¦æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡è¢«è§£å°æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doUntieDisable(String loginType, Object loginId, String service) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡æå¼äºçº§è®¤è¯æ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡å建Sessionæ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doCloseSafe(String loginType, String tokenValue, String service) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡å建Sessionæ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doCreateSession(String id) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡æ³¨éSessionæ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doLogoutSession(String id) { |
| | | } |
| | | |
| | | /** |
| | | * æ¯æ¬¡Tokenç»ææ¶è§¦å |
| | | */ |
| | | @Override |
| | | public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.satoken.utils; |
| | | |
| | | import cn.dev33.satoken.context.SaHolder; |
| | | import cn.dev33.satoken.context.model.SaStorage; |
| | | import cn.dev33.satoken.stp.SaLoginModel; |
| | | import cn.dev33.satoken.stp.StpUtil; |
| | | import cn.hutool.core.convert.Convert; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import org.dromara.common.core.constant.TenantConstants; |
| | | import org.dromara.common.core.constant.UserConstants; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.core.enums.DeviceType; |
| | | import org.dromara.common.core.enums.UserType; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * ç»å½é´æå©æ |
| | | * <p> |
| | | * user_type 为 ç¨æ·ç±»å åä¸ä¸ªç¨æ·è¡¨ å¯ä»¥æå¤ç§ç¨æ·ç±»å ä¾å¦ pc,app |
| | | * deivce 为 设å¤ç±»å åä¸ä¸ªç¨æ·ç±»å å¯ä»¥æ å¤ç§è®¾å¤ç±»å ä¾å¦ web,ios |
| | | * å¯ä»¥ç»æ ç¨æ·ç±»åä¸è®¾å¤ç±»åå¤å¯¹å¤ç æéçµæ´»æ§å¶ |
| | | * <p> |
| | | * å¤ç¨æ·ä½ç³» é对 å¤ç§ç¨æ·ç±»å 使鿧å¶ä¸ä¸è´ |
| | | * å¯ä»¥ç»æ å¤ç¨æ·ç±»å表ä¸å¤è®¾å¤ç±»å å嫿§å¶æé |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class LoginHelper { |
| | | |
| | | public static final String LOGIN_USER_KEY = "loginUser"; |
| | | public static final String TENANT_KEY = "tenantId"; |
| | | public static final String USER_KEY = "userId"; |
| | | |
| | | /** |
| | | * ç»å½ç³»ç» |
| | | * |
| | | * @param loginUser ç»å½ç¨æ·ä¿¡æ¯ |
| | | */ |
| | | public static void login(LoginUser loginUser) { |
| | | loginByDevice(loginUser, null); |
| | | } |
| | | |
| | | /** |
| | | * ç»å½ç³»ç» åºäº 设å¤ç±»å |
| | | * é对ç¸åç¨æ·ä½ç³»ä¸åè®¾å¤ |
| | | * |
| | | * @param loginUser ç»å½ç¨æ·ä¿¡æ¯ |
| | | */ |
| | | public static void loginByDevice(LoginUser loginUser, DeviceType deviceType) { |
| | | SaStorage storage = SaHolder.getStorage(); |
| | | storage.set(LOGIN_USER_KEY, loginUser); |
| | | storage.set(TENANT_KEY, loginUser.getTenantId()); |
| | | storage.set(USER_KEY, loginUser.getUserId()); |
| | | SaLoginModel model = new SaLoginModel(); |
| | | if (ObjectUtil.isNotNull(deviceType)) { |
| | | model.setDevice(deviceType.getDevice()); |
| | | } |
| | | StpUtil.login(loginUser.getLoginId(), |
| | | model.setExtra(TENANT_KEY, loginUser.getTenantId()) |
| | | .setExtra(USER_KEY, loginUser.getUserId())); |
| | | StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser); |
| | | } |
| | | |
| | | /** |
| | | * è·åç¨æ·(å¤çº§ç¼å) |
| | | */ |
| | | public static LoginUser getLoginUser() { |
| | | LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY); |
| | | if (loginUser != null) { |
| | | return loginUser; |
| | | } |
| | | loginUser = (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY); |
| | | SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); |
| | | return loginUser; |
| | | } |
| | | |
| | | /** |
| | | * è·åç¨æ·åºäºtoken |
| | | */ |
| | | public static LoginUser getLoginUser(String token) { |
| | | return (LoginUser) StpUtil.getTokenSessionByToken(token).get(LOGIN_USER_KEY); |
| | | } |
| | | |
| | | /** |
| | | * è·åç¨æ·id |
| | | */ |
| | | public static Long getUserId() { |
| | | Long userId; |
| | | try { |
| | | userId = Convert.toLong(SaHolder.getStorage().get(USER_KEY)); |
| | | if (ObjectUtil.isNull(userId)) { |
| | | userId = Convert.toLong(StpUtil.getExtra(USER_KEY)); |
| | | SaHolder.getStorage().set(USER_KEY, userId); |
| | | } |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | return userId; |
| | | } |
| | | |
| | | /** |
| | | * è·åç§æ·ID |
| | | */ |
| | | public static String getTenantId() { |
| | | String tenantId; |
| | | try { |
| | | tenantId = (String) SaHolder.getStorage().get(TENANT_KEY); |
| | | if (ObjectUtil.isNull(tenantId)) { |
| | | tenantId = (String) StpUtil.getExtra(TENANT_KEY); |
| | | SaHolder.getStorage().set(TENANT_KEY, tenantId); |
| | | } |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | return tenantId; |
| | | } |
| | | |
| | | /** |
| | | * è·åé¨é¨ID |
| | | */ |
| | | public static Long getDeptId() { |
| | | return getLoginUser().getDeptId(); |
| | | } |
| | | |
| | | /** |
| | | * è·åç¨æ·è´¦æ· |
| | | */ |
| | | public static String getUsername() { |
| | | return getLoginUser().getUsername(); |
| | | } |
| | | |
| | | /** |
| | | * è·åç¨æ·ç±»å |
| | | */ |
| | | public static UserType getUserType() { |
| | | String loginId = StpUtil.getLoginIdAsString(); |
| | | return UserType.getUserType(loginId); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºè¶
级管çå |
| | | * |
| | | * @param userId ç¨æ·ID |
| | | * @return ç»æ |
| | | */ |
| | | public static boolean isSuperAdmin(Long userId) { |
| | | return UserConstants.SUPER_ADMIN_ID.equals(userId); |
| | | } |
| | | |
| | | public static boolean isSuperAdmin() { |
| | | return isSuperAdmin(getUserId()); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºè¶
级管çå |
| | | * |
| | | * @param rolePermission è§è²æéæ è¯ç» |
| | | * @return ç»æ |
| | | */ |
| | | public static boolean isTenantAdmin(Set<String> rolePermission) { |
| | | return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY); |
| | | } |
| | | |
| | | public static boolean isTenantAdmin() { |
| | | return isTenantAdmin(getLoginUser().getRolePermission()); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.satoken.config.SaTokenConfig |
| | | org.dromara.common.satoken.config.SaTokenConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-satoken</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.security.config; |
| | | |
| | | import cn.dev33.satoken.interceptor.SaInterceptor; |
| | | import cn.dev33.satoken.router.SaRouter; |
| | | import cn.dev33.satoken.stp.StpUtil; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.security.config.properties.SecurityProperties; |
| | | import org.dromara.common.security.handler.AllUrlHandler; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
| | | |
| | | /** |
| | | * æéå®å
¨é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | |
| | | @Slf4j |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(SecurityProperties.class) |
| | | @RequiredArgsConstructor |
| | | public class SecurityConfig implements WebMvcConfigurer { |
| | | |
| | | private final SecurityProperties securityProperties; |
| | | |
| | | /** |
| | | * 注åsa-tokençæ¦æªå¨ |
| | | */ |
| | | @Override |
| | | public void addInterceptors(InterceptorRegistry registry) { |
| | | // 注åè·¯ç±æ¦æªå¨ï¼èªå®ä¹éªè¯è§å |
| | | registry.addInterceptor(new SaInterceptor(handler -> { |
| | | AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); |
| | | // ç»å½éªè¯ -- æé¤å¤ä¸ªè·¯å¾ |
| | | SaRouter |
| | | // è·åææç |
| | | .match(allUrlHandler.getUrls()) |
| | | // å¯¹æªæé¤çè·¯å¾è¿è¡æ£æ¥ |
| | | .check(() -> { |
| | | // æ£æ¥æ¯å¦ç»å½ æ¯å¦ætoken |
| | | StpUtil.checkLogin(); |
| | | |
| | | // ææçå½±å ç¨äºä¸´æ¶æµè¯ |
| | | // if (log.isDebugEnabled()) { |
| | | // log.debug("å©ä½æææ¶é´: {}", StpUtil.getTokenTimeout()); |
| | | // log.debug("ä¸´æ¶æææ¶é´: {}", StpUtil.getTokenActivityTimeout()); |
| | | // } |
| | | |
| | | }); |
| | | })).addPathPatterns("/**") |
| | | // æé¤ä¸éè¦æ¦æªçè·¯å¾ |
| | | .excludePathPatterns(securityProperties.getExcludes()); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.security.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * Security é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "security") |
| | | public class SecurityProperties { |
| | | |
| | | /** |
| | | * æé¤è·¯å¾ |
| | | */ |
| | | private String[] excludes; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.security.handler; |
| | | |
| | | import cn.hutool.core.util.ReUtil; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import lombok.Data; |
| | | import org.springframework.beans.factory.InitializingBean; |
| | | import org.springframework.web.method.HandlerMethod; |
| | | import org.springframework.web.servlet.mvc.method.RequestMappingInfo; |
| | | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; |
| | | |
| | | import java.util.*; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * è·åææUrlé
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | public class AllUrlHandler implements InitializingBean { |
| | | |
| | | private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); |
| | | |
| | | private List<String> urls = new ArrayList<>(); |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() { |
| | | Set<String> set = new HashSet<>(); |
| | | RequestMappingHandlerMapping mapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); |
| | | Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods(); |
| | | map.keySet().forEach(info -> { |
| | | // è·å注解ä¸è¾¹ç path æ¿ä»£ path variable 为 * |
| | | Objects.requireNonNull(info.getPathPatternsCondition().getPatterns()) |
| | | .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*"))); |
| | | }); |
| | | urls.addAll(set); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.security.handler; |
| | | |
| | | import cn.dev33.satoken.exception.NotLoginException; |
| | | import cn.dev33.satoken.exception.NotPermissionException; |
| | | import cn.dev33.satoken.exception.NotRoleException; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.http.HttpStatus; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.exception.DemoModeException; |
| | | import org.dromara.common.core.exception.ServiceException; |
| | | import org.dromara.common.core.utils.StreamUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.support.DefaultMessageSourceResolvable; |
| | | import org.springframework.validation.BindException; |
| | | import org.springframework.web.HttpRequestMethodNotSupportedException; |
| | | import org.springframework.web.bind.MethodArgumentNotValidException; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | | import org.springframework.web.bind.annotation.RestControllerAdvice; |
| | | |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.validation.ConstraintViolation; |
| | | import jakarta.validation.ConstraintViolationException; |
| | | |
| | | /** |
| | | * å
¨å±å¼å¸¸å¤çå¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @RestControllerAdvice |
| | | public class GlobalExceptionHandler { |
| | | |
| | | /** |
| | | * æéç å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(NotPermissionException.class) |
| | | public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',æéç æ ¡éªå¤±è´¥'{}'", requestURI, e.getMessage()); |
| | | return R.fail(HttpStatus.HTTP_FORBIDDEN, "没æè®¿é®æéï¼è¯·è系管çåææ"); |
| | | } |
| | | |
| | | /** |
| | | * è§è²æéå¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(NotRoleException.class) |
| | | public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',è§è²æéæ ¡éªå¤±è´¥'{}'", requestURI, e.getMessage()); |
| | | return R.fail(HttpStatus.HTTP_FORBIDDEN, "没æè®¿é®æéï¼è¯·è系管çåææ"); |
| | | } |
| | | |
| | | /** |
| | | * 认è¯å¤±è´¥ |
| | | */ |
| | | @ExceptionHandler(NotLoginException.class) |
| | | public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',认è¯å¤±è´¥'{}',æ æ³è®¿é®ç³»ç»èµæº", requestURI, e.getMessage()); |
| | | return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认è¯å¤±è´¥ï¼æ æ³è®¿é®ç³»ç»èµæº"); |
| | | } |
| | | |
| | | /** |
| | | * è¯·æ±æ¹å¼ä¸æ¯æ |
| | | */ |
| | | @ExceptionHandler(HttpRequestMethodNotSupportedException.class) |
| | | public R<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, |
| | | HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',䏿¯æ'{}'请æ±", requestURI, e.getMethod()); |
| | | return R.fail(e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * ä¸å¡å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(ServiceException.class) |
| | | public R<Void> handleServiceException(ServiceException e, HttpServletRequest request) { |
| | | log.error(e.getMessage(), e); |
| | | Integer code = e.getCode(); |
| | | return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * æ¦æªæªç¥çè¿è¡æ¶å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(RuntimeException.class) |
| | | public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',åçæªç¥å¼å¸¸.", requestURI, e); |
| | | return R.fail(e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * ç³»ç»å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(Exception.class) |
| | | public R<Void> handleException(Exception e, HttpServletRequest request) { |
| | | String requestURI = request.getRequestURI(); |
| | | log.error("请æ±å°å'{}',åçç³»ç»å¼å¸¸.", requestURI, e); |
| | | return R.fail(e.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹éªè¯å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(BindException.class) |
| | | public R<Void> handleBindException(BindException e) { |
| | | log.error(e.getMessage(), e); |
| | | String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", "); |
| | | return R.fail(message); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹éªè¯å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(ConstraintViolationException.class) |
| | | public R<Void> constraintViolationException(ConstraintViolationException e) { |
| | | log.error(e.getMessage(), e); |
| | | String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", "); |
| | | return R.fail(message); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹éªè¯å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(MethodArgumentNotValidException.class) |
| | | public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { |
| | | log.error(e.getMessage(), e); |
| | | String message = e.getBindingResult().getFieldError().getDefaultMessage(); |
| | | return R.fail(message); |
| | | } |
| | | |
| | | /** |
| | | * æ¼ç¤ºæ¨¡å¼å¼å¸¸ |
| | | */ |
| | | @ExceptionHandler(DemoModeException.class) |
| | | public R<Void> handleDemoModeException(DemoModeException e) { |
| | | return R.fail("æ¼ç¤ºæ¨¡å¼ï¼ä¸å
许æä½"); |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.security.handler.GlobalExceptionHandler |
| | | com.ruoyi.common.security.handler.AllUrlHandler |
| | | com.ruoyi.common.security.config.SecurityConfig |
| | | org.dromara.common.security.handler.GlobalExceptionHandler |
| | | org.dromara.common.security.handler.AllUrlHandler |
| | | org.dromara.common.security.config.SecurityConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | </dependencies> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sensitive.annotation; |
| | | |
| | | import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; |
| | | import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
| | | import org.dromara.common.sensitive.core.SensitiveStrategy; |
| | | import org.dromara.common.sensitive.handler.SensitiveHandler; |
| | | |
| | | import java.lang.annotation.ElementType; |
| | | import java.lang.annotation.Retention; |
| | | import java.lang.annotation.RetentionPolicy; |
| | | import java.lang.annotation.Target; |
| | | |
| | | /** |
| | | * æ°æ®è±ææ³¨è§£ |
| | | * |
| | | * @author zhujie |
| | | */ |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target(ElementType.FIELD) |
| | | @JacksonAnnotationsInside |
| | | @JsonSerialize(using = SensitiveHandler.class) |
| | | public @interface Sensitive { |
| | | SensitiveStrategy strategy(); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sensitive.core; |
| | | |
| | | /** |
| | | * è±ææå¡ |
| | | * é»è®¤ç®¡çåä¸è¿æ»¤ |
| | | * éèªè¡æ ¹æ®ä¸å¡éåå®ç° |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | */ |
| | | public interface SensitiveService { |
| | | |
| | | /** |
| | | * æ¯å¦è±æ |
| | | */ |
| | | boolean isSensitive(); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sensitive.core; |
| | | |
| | | import cn.hutool.core.util.DesensitizedUtil; |
| | | import lombok.AllArgsConstructor; |
| | | |
| | | import java.util.function.Function; |
| | | |
| | | /** |
| | | * è±æçç¥ |
| | | * |
| | | * @author Yjoioooo |
| | | * @version 3.6.0 |
| | | */ |
| | | @AllArgsConstructor |
| | | public enum SensitiveStrategy { |
| | | |
| | | /** |
| | | * 身份è¯è±æ |
| | | */ |
| | | ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)), |
| | | |
| | | /** |
| | | * ææºå·è±æ |
| | | */ |
| | | PHONE(DesensitizedUtil::mobilePhone), |
| | | |
| | | /** |
| | | * å°åè±æ |
| | | */ |
| | | ADDRESS(s -> DesensitizedUtil.address(s, 8)), |
| | | |
| | | /** |
| | | * é®ç®±è±æ |
| | | */ |
| | | EMAIL(DesensitizedUtil::email), |
| | | |
| | | /** |
| | | * é¶è¡å¡ |
| | | */ |
| | | BANK_CARD(DesensitizedUtil::bankCard); |
| | | |
| | | //å¯èªè¡æ·»å å
¶ä»è±æçç¥ |
| | | |
| | | private final Function<String, String> desensitizer; |
| | | |
| | | public Function<String, String> desensitizer() { |
| | | return desensitizer; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sensitive.handler; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.fasterxml.jackson.core.JsonGenerator; |
| | | import com.fasterxml.jackson.databind.BeanProperty; |
| | | import com.fasterxml.jackson.databind.JsonMappingException; |
| | | import com.fasterxml.jackson.databind.JsonSerializer; |
| | | import com.fasterxml.jackson.databind.SerializerProvider; |
| | | import com.fasterxml.jackson.databind.ser.ContextualSerializer; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.sensitive.annotation.Sensitive; |
| | | import org.dromara.common.sensitive.core.SensitiveService; |
| | | import org.dromara.common.sensitive.core.SensitiveStrategy; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.BeansException; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * æ°æ®è±æjsonåºååå·¥å
· |
| | | * |
| | | * @author Yjoioooo |
| | | */ |
| | | @Slf4j |
| | | public class SensitiveHandler extends JsonSerializer<String> implements ContextualSerializer { |
| | | |
| | | private SensitiveStrategy strategy; |
| | | |
| | | @Override |
| | | public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { |
| | | try { |
| | | SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class); |
| | | if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) { |
| | | gen.writeString(strategy.desensitizer().apply(value)); |
| | | } else { |
| | | gen.writeString(value); |
| | | } |
| | | } catch (BeansException e) { |
| | | log.error("è±æå®ç°ä¸åå¨, éç¨é»è®¤å¤ç => {}", e.getMessage()); |
| | | gen.writeString(value); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { |
| | | Sensitive annotation = property.getAnnotation(Sensitive.class); |
| | | if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { |
| | | this.strategy = annotation.strategy(); |
| | | return this; |
| | | } |
| | | return prov.findValueSerializer(property.getType(), property); |
| | | } |
| | | } |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.config; |
| | | |
| | | import org.dromara.common.sms.config.properties.SmsProperties; |
| | | import org.dromara.common.sms.core.AliyunSmsTemplate; |
| | | import org.dromara.common.sms.core.SmsTemplate; |
| | | import org.dromara.common.sms.core.TencentSmsTemplate; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | /** |
| | | * çä¿¡é
置类 |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(SmsProperties.class) |
| | | public class SmsConfig { |
| | | |
| | | @Configuration |
| | | @ConditionalOnProperty(value = "sms.enabled", havingValue = "true") |
| | | @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class) |
| | | static class AliyunSmsConfig { |
| | | |
| | | @Bean |
| | | public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) { |
| | | return new AliyunSmsTemplate(smsProperties); |
| | | } |
| | | |
| | | } |
| | | |
| | | @Configuration |
| | | @ConditionalOnProperty(value = "sms.enabled", havingValue = "true") |
| | | @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class) |
| | | static class TencentSmsConfig { |
| | | |
| | | @Bean |
| | | public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) { |
| | | return new TencentSmsTemplate(smsProperties); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * SMSçä¿¡ é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "sms") |
| | | public class SmsProperties { |
| | | |
| | | private Boolean enabled; |
| | | |
| | | /** |
| | | * é
ç½®èç¹ |
| | | * é¿éäº dysmsapi.aliyuncs.com |
| | | * è
¾è®¯äº sms.tencentcloudapi.com |
| | | */ |
| | | private String endpoint; |
| | | |
| | | /** |
| | | * key |
| | | */ |
| | | private String accessKeyId; |
| | | |
| | | /** |
| | | * å¯å |
| | | */ |
| | | private String accessKeySecret; |
| | | |
| | | /* |
| | | * çä¿¡ç¾å |
| | | */ |
| | | private String signName; |
| | | |
| | | /** |
| | | * çä¿¡åºç¨ID (è
¾è®¯ä¸å±) |
| | | */ |
| | | private String sdkAppId; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.core; |
| | | |
| | | import com.aliyun.dysmsapi20170525.Client; |
| | | import com.aliyun.dysmsapi20170525.models.SendSmsRequest; |
| | | import com.aliyun.dysmsapi20170525.models.SendSmsResponse; |
| | | import com.aliyun.teaopenapi.models.Config; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.sms.config.properties.SmsProperties; |
| | | import org.dromara.common.sms.entity.SmsResult; |
| | | import org.dromara.common.sms.exception.SmsException; |
| | | import lombok.SneakyThrows; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Aliyun çä¿¡æ¨¡æ¿ |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | public class AliyunSmsTemplate implements SmsTemplate { |
| | | |
| | | private SmsProperties properties; |
| | | |
| | | private Client client; |
| | | |
| | | @SneakyThrows(Exception.class) |
| | | public AliyunSmsTemplate(SmsProperties smsProperties) { |
| | | this.properties = smsProperties; |
| | | Config config = new Config() |
| | | // æ¨çAccessKey ID |
| | | .setAccessKeyId(smsProperties.getAccessKeyId()) |
| | | // æ¨çAccessKey Secret |
| | | .setAccessKeySecret(smsProperties.getAccessKeySecret()) |
| | | // 访é®çåå |
| | | .setEndpoint(smsProperties.getEndpoint()); |
| | | this.client = new Client(config); |
| | | } |
| | | |
| | | @Override |
| | | public SmsResult send(String phones, String templateId, Map<String, String> param) { |
| | | if (StringUtils.isBlank(phones)) { |
| | | throw new SmsException("ææºå·ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (StringUtils.isBlank(templateId)) { |
| | | throw new SmsException("模æ¿IDä¸è½ä¸ºç©º"); |
| | | } |
| | | SendSmsRequest req = new SendSmsRequest() |
| | | .setPhoneNumbers(phones) |
| | | .setSignName(properties.getSignName()) |
| | | .setTemplateCode(templateId) |
| | | .setTemplateParam(JsonUtils.toJsonString(param)); |
| | | try { |
| | | SendSmsResponse resp = client.sendSms(req); |
| | | return SmsResult.builder() |
| | | .isSuccess("OK".equals(resp.getBody().getCode())) |
| | | .message(resp.getBody().getMessage()) |
| | | .response(JsonUtils.toJsonString(resp)) |
| | | .build(); |
| | | } catch (Exception e) { |
| | | throw new SmsException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.core; |
| | | |
| | | import org.dromara.common.sms.entity.SmsResult; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * çä¿¡æ¨¡æ¿ |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | public interface SmsTemplate { |
| | | |
| | | /** |
| | | * åéçä¿¡ |
| | | * |
| | | * @param phones çµè¯å·(å¤ä¸ªéå·åå²) |
| | | * @param templateId 模æ¿id |
| | | * @param param 模æ¿å¯¹åºåæ° |
| | | * é¿é éä½¿ç¨ æ¨¡æ¿åéå称对åºå
容 ä¾å¦: code=1234 |
| | | * è
¾è®¯ éä½¿ç¨ æ¨¡æ¿åé顺åºå¯¹åºå
容 ä¾å¦: 1=1234, 1为模æ¿å
第ä¸ä¸ªåæ° |
| | | */ |
| | | SmsResult send(String phones, String templateId, Map<String, String> param); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.core; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.sms.config.properties.SmsProperties; |
| | | import org.dromara.common.sms.entity.SmsResult; |
| | | import org.dromara.common.sms.exception.SmsException; |
| | | import com.tencentcloudapi.common.Credential; |
| | | import com.tencentcloudapi.common.profile.ClientProfile; |
| | | import com.tencentcloudapi.common.profile.HttpProfile; |
| | | import com.tencentcloudapi.sms.v20190711.SmsClient; |
| | | import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; |
| | | import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse; |
| | | import com.tencentcloudapi.sms.v20190711.models.SendStatus; |
| | | import lombok.SneakyThrows; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * Tencent çä¿¡æ¨¡æ¿ |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | public class TencentSmsTemplate implements SmsTemplate { |
| | | |
| | | private SmsProperties properties; |
| | | |
| | | private SmsClient client; |
| | | |
| | | @SneakyThrows(Exception.class) |
| | | public TencentSmsTemplate(SmsProperties smsProperties) { |
| | | this.properties = smsProperties; |
| | | Credential credential = new Credential(smsProperties.getAccessKeyId(), smsProperties.getAccessKeySecret()); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | httpProfile.setEndpoint(smsProperties.getEndpoint()); |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | clientProfile.setHttpProfile(httpProfile); |
| | | this.client = new SmsClient(credential, "", clientProfile); |
| | | } |
| | | |
| | | @Override |
| | | public SmsResult send(String phones, String templateId, Map<String, String> param) { |
| | | if (StringUtils.isBlank(phones)) { |
| | | throw new SmsException("ææºå·ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (StringUtils.isBlank(templateId)) { |
| | | throw new SmsException("模æ¿IDä¸è½ä¸ºç©º"); |
| | | } |
| | | SendSmsRequest req = new SendSmsRequest(); |
| | | Set<String> set = Arrays.stream(phones.split(StringUtils.SEPARATOR)).map(p -> "+86" + p).collect(Collectors.toSet()); |
| | | req.setPhoneNumberSet(ArrayUtil.toArray(set, String.class)); |
| | | if (CollUtil.isNotEmpty(param)) { |
| | | req.setTemplateParamSet(ArrayUtil.toArray(param.values(), String.class)); |
| | | } |
| | | req.setTemplateID(templateId); |
| | | req.setSign(properties.getSignName()); |
| | | req.setSmsSdkAppid(properties.getSdkAppId()); |
| | | try { |
| | | SendSmsResponse resp = client.SendSms(req); |
| | | SmsResult.SmsResultBuilder builder = SmsResult.builder() |
| | | .isSuccess(true) |
| | | .message("send success") |
| | | .response(JsonUtils.toJsonString(resp)); |
| | | for (SendStatus sendStatus : resp.getSendStatusSet()) { |
| | | if (!"Ok".equals(sendStatus.getCode())) { |
| | | builder.isSuccess(false).message(sendStatus.getMessage()); |
| | | break; |
| | | } |
| | | } |
| | | return builder.build(); |
| | | } catch (Exception e) { |
| | | throw new SmsException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.entity; |
| | | |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ä¸ä¼ è¿åä½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @Builder |
| | | public class SmsResult { |
| | | |
| | | /** |
| | | * æ¯å¦æå |
| | | */ |
| | | private boolean isSuccess; |
| | | |
| | | /** |
| | | * ååºæ¶æ¯ |
| | | */ |
| | | private String message; |
| | | |
| | | /** |
| | | * å®é
ååºä½ |
| | | * <p> |
| | | * å¯èªè¡è½¬æ¢ä¸º SDK 对åºç SendSmsResponse |
| | | */ |
| | | private String response; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.sms.exception; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * Smså¼å¸¸ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class SmsException extends RuntimeException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public SmsException(String msg) { |
| | | super(msg); |
| | | } |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.sms.config.SmsConfig |
| | | org.dromara.common.sms.config.SmsConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.config; |
| | | |
| | | import cn.dev33.satoken.dao.SaTokenDao; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| | | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; |
| | | import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; |
| | | import org.dromara.common.core.utils.reflect.ReflectUtils; |
| | | import org.dromara.common.mybatis.config.MybatisPlusConfig; |
| | | import org.dromara.common.redis.config.RedisConfig; |
| | | import org.dromara.common.redis.config.properties.RedissonProperties; |
| | | import org.dromara.common.tenant.core.TenantSaTokenDao; |
| | | import org.dromara.common.tenant.handle.PlusTenantLineHandler; |
| | | import org.dromara.common.tenant.handle.TenantKeyPrefixHandler; |
| | | import org.dromara.common.tenant.manager.TenantSpringCacheManager; |
| | | import org.dromara.common.tenant.properties.TenantProperties; |
| | | import org.redisson.config.ClusterServersConfig; |
| | | import org.redisson.config.SingleServerConfig; |
| | | import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.cache.CacheManager; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Primary; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç§æ·é
置类 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @EnableConfigurationProperties(TenantProperties.class) |
| | | @AutoConfiguration(after = {RedisConfig.class, MybatisPlusConfig.class}) |
| | | @ConditionalOnProperty(value = "tenant.enable", havingValue = "true") |
| | | public class TenantConfig { |
| | | |
| | | /** |
| | | * åå§åç§æ·é
ç½® |
| | | */ |
| | | @Bean |
| | | public boolean tenantInit(MybatisPlusInterceptor mybatisPlusInterceptor, |
| | | TenantProperties tenantProperties) { |
| | | List<InnerInterceptor> interceptors = new ArrayList<>(); |
| | | // å¤ç§æ·æä»¶ å¿
é¡»æ¾å°ç¬¬ä¸ä½ |
| | | interceptors.add(tenantLineInnerInterceptor(tenantProperties)); |
| | | interceptors.addAll(mybatisPlusInterceptor.getInterceptors()); |
| | | mybatisPlusInterceptor.setInterceptors(interceptors); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * å¤ç§æ·æä»¶ |
| | | */ |
| | | public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) { |
| | | return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties)); |
| | | } |
| | | |
| | | @Bean |
| | | public RedissonAutoConfigurationCustomizer tenantRedissonCustomizer(RedissonProperties redissonProperties) { |
| | | return config -> { |
| | | TenantKeyPrefixHandler nameMapper = new TenantKeyPrefixHandler(redissonProperties.getKeyPrefix()); |
| | | SingleServerConfig singleServerConfig = ReflectUtils.invokeGetter(config, "singleServerConfig"); |
| | | if (ObjectUtil.isNotNull(singleServerConfig)) { |
| | | // 使ç¨åæºæ¨¡å¼ |
| | | // 设置å¤ç§æ· redis keyåç¼ |
| | | singleServerConfig.setNameMapper(nameMapper); |
| | | ReflectUtils.invokeSetter(config, "singleServerConfig", singleServerConfig); |
| | | } |
| | | ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig"); |
| | | // é群é
ç½®æ¹å¼ åè䏿¹æ³¨é |
| | | if (ObjectUtil.isNotNull(clusterServersConfig)) { |
| | | // 设置å¤ç§æ· redis keyåç¼ |
| | | clusterServersConfig.setNameMapper(nameMapper); |
| | | ReflectUtils.invokeSetter(config, "clusterServersConfig", clusterServersConfig); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * å¤ç§æ·ç¼å管çå¨ |
| | | */ |
| | | @Primary |
| | | @Bean |
| | | public CacheManager tenantCacheManager() { |
| | | return new TenantSpringCacheManager(); |
| | | } |
| | | |
| | | /** |
| | | * å¤ç§æ·é´ædaoå®ç° |
| | | */ |
| | | @Primary |
| | | @Bean |
| | | public SaTokenDao tenantSaTokenDao() { |
| | | return new TenantSaTokenDao(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.core; |
| | | |
| | | import org.dromara.common.mybatis.core.domain.BaseEntity; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * ç§æ·åºç±» |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class TenantEntity extends BaseEntity { |
| | | |
| | | /** |
| | | * ç§æ·ç¼å· |
| | | */ |
| | | private String tenantId; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.core; |
| | | |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.satoken.core.dao.PlusSaTokenDao; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * SaToken è®¤è¯æ°æ®æä¹
å± éé
å¤ç§æ· |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class TenantSaTokenDao extends PlusSaTokenDao { |
| | | |
| | | @Override |
| | | public String get(String key) { |
| | | return super.get(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | @Override |
| | | public void set(String key, String value, long timeout) { |
| | | super.set(GlobalConstants.GLOBAL_REDIS_KEY + key, value, timeout); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®ä¿®æ¹æå®key-valueé®å¼å¯¹ (è¿ææ¶é´ä¸å) |
| | | */ |
| | | @Override |
| | | public void update(String key, String value) { |
| | | long expire = getTimeout(key); |
| | | // -2 = æ æ¤é® |
| | | if (expire == NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | this.set(key, value, expire); |
| | | } |
| | | |
| | | /** |
| | | * å é¤Value |
| | | */ |
| | | @Override |
| | | public void delete(String key) { |
| | | super.delete(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | /** |
| | | * è·åValueçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public long getTimeout(String key) { |
| | | return super.getTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹Valueçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void updateTimeout(String key, long timeout) { |
| | | // 夿æ¯å¦æ³è¦è®¾ç½®ä¸ºæ°¸ä¹
|
| | | if (timeout == NEVER_EXPIRE) { |
| | | long expire = getTimeout(key); |
| | | if (expire == NEVER_EXPIRE) { |
| | | // 妿å
¶å·²ç»è¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼åä¸ä½ä»»ä½å¤ç |
| | | } else { |
| | | // 妿尿ªè¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼é£ä¹å次set䏿¬¡ |
| | | this.set(key, this.get(key), timeout); |
| | | } |
| | | return; |
| | | } |
| | | RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * è·åObjectï¼å¦æ è¿ç©º |
| | | */ |
| | | @Override |
| | | public Object getObject(String key) { |
| | | return super.getObject(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | /** |
| | | * åå
¥Objectï¼å¹¶è®¾å®åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void setObject(String key, Object object, long timeout) { |
| | | super.setObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object, timeout); |
| | | } |
| | | |
| | | /** |
| | | * æ´æ°Object (è¿ææ¶é´ä¸å) |
| | | */ |
| | | @Override |
| | | public void updateObject(String key, Object object) { |
| | | long expire = getObjectTimeout(key); |
| | | // -2 = æ æ¤é® |
| | | if (expire == NOT_VALUE_EXPIRE) { |
| | | return; |
| | | } |
| | | this.setObject(key, object, expire); |
| | | } |
| | | |
| | | /** |
| | | * å é¤Object |
| | | */ |
| | | @Override |
| | | public void deleteObject(String key) { |
| | | super.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | /** |
| | | * è·åObjectçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public long getObjectTimeout(String key) { |
| | | return super.getObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹Objectçå©ä½åæ´»æ¶é´ (åä½: ç§) |
| | | */ |
| | | @Override |
| | | public void updateObjectTimeout(String key, long timeout) { |
| | | // 夿æ¯å¦æ³è¦è®¾ç½®ä¸ºæ°¸ä¹
|
| | | if (timeout == NEVER_EXPIRE) { |
| | | long expire = getObjectTimeout(key); |
| | | if (expire == NEVER_EXPIRE) { |
| | | // 妿å
¶å·²ç»è¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼åä¸ä½ä»»ä½å¤ç |
| | | } else { |
| | | // 妿尿ªè¢«è®¾ç½®ä¸ºæ°¸ä¹
ï¼é£ä¹å次set䏿¬¡ |
| | | this.setObject(key, this.getObject(key), timeout); |
| | | } |
| | | return; |
| | | } |
| | | RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * æç´¢æ°æ® |
| | | */ |
| | | @Override |
| | | public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) { |
| | | return super.searchData(GlobalConstants.GLOBAL_REDIS_KEY + prefix, keyword, start, size, sortType); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.exception; |
| | | |
| | | import org.dromara.common.core.exception.base.BaseException; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * ç§æ·å¼å¸¸ç±» |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class TenantException extends BaseException { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public TenantException(String code, Object... args) { |
| | | super("tenant", code, args, null); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.handle; |
| | | |
| | | import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | import org.dromara.common.tenant.properties.TenantProperties; |
| | | import lombok.AllArgsConstructor; |
| | | import net.sf.jsqlparser.expression.Expression; |
| | | import net.sf.jsqlparser.expression.NullValue; |
| | | import net.sf.jsqlparser.expression.StringValue; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * èªå®ä¹ç§æ·å¤çå¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | public class PlusTenantLineHandler implements TenantLineHandler { |
| | | |
| | | private final TenantProperties tenantProperties; |
| | | |
| | | @Override |
| | | public Expression getTenantId() { |
| | | String tenantId = LoginHelper.getTenantId(); |
| | | if (StringUtils.isBlank(tenantId)) { |
| | | return new NullValue(); |
| | | } |
| | | String dynamicTenantId = TenantHelper.getDynamic(); |
| | | if (StringUtils.isNotBlank(dynamicTenantId)) { |
| | | // è¿åå¨æç§æ· |
| | | return new StringValue(dynamicTenantId); |
| | | } |
| | | // è¿ååºå®ç§æ· |
| | | return new StringValue(tenantId); |
| | | } |
| | | |
| | | @Override |
| | | public boolean ignoreTable(String tableName) { |
| | | String tenantId = LoginHelper.getTenantId(); |
| | | // 夿æ¯å¦æç§æ· |
| | | if (StringUtils.isNotBlank(tenantId)) { |
| | | // ä¸éè¦è¿æ»¤ç§æ·ç表 |
| | | List<String> excludes = tenantProperties.getExcludes(); |
| | | // éä¸å¡è¡¨ |
| | | excludes.addAll(List.of( |
| | | "gen_table", |
| | | "gen_table_column" |
| | | )); |
| | | return excludes.contains(tableName); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.handle; |
| | | |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.redis.handler.KeyPrefixHandler; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | |
| | | /** |
| | | * å¤ç§æ·redisç¼åkeyåç¼å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class TenantKeyPrefixHandler extends KeyPrefixHandler { |
| | | |
| | | public TenantKeyPrefixHandler(String keyPrefix) { |
| | | super(keyPrefix); |
| | | } |
| | | |
| | | /** |
| | | * å¢å åç¼ |
| | | */ |
| | | @Override |
| | | public String map(String name) { |
| | | if (StringUtils.isBlank(name)) { |
| | | return null; |
| | | } |
| | | if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { |
| | | return super.map(name); |
| | | } |
| | | String tenantId = TenantHelper.getTenantId(); |
| | | if (StringUtils.startsWith(name, tenantId)) { |
| | | // 妿åå¨åç´æ¥è¿å |
| | | return super.map(name); |
| | | } |
| | | return super.map(tenantId + ":" + name); |
| | | } |
| | | |
| | | /** |
| | | * å»é¤åç¼ |
| | | */ |
| | | @Override |
| | | public String unmap(String name) { |
| | | String unmap = super.unmap(name); |
| | | if (StringUtils.isBlank(unmap)) { |
| | | return null; |
| | | } |
| | | if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { |
| | | return super.unmap(name); |
| | | } |
| | | String tenantId = TenantHelper.getTenantId(); |
| | | if (StringUtils.startsWith(unmap, tenantId)) { |
| | | // 妿åå¨åå é¤ |
| | | return unmap.substring((tenantId + ":").length()); |
| | | } |
| | | return unmap; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.helper; |
| | | |
| | | import cn.dev33.satoken.context.SaHolder; |
| | | import cn.dev33.satoken.spring.SpringMVCUtil; |
| | | import cn.hutool.core.convert.Convert; |
| | | import com.alibaba.ttl.TransmittableThreadLocal; |
| | | import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; |
| | | import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | /** |
| | | * ç§æ·å©æ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class TenantHelper { |
| | | |
| | | private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; |
| | | |
| | | private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>(); |
| | | |
| | | /** |
| | | * ç§æ·åè½æ¯å¦å¯ç¨ |
| | | */ |
| | | public static boolean isEnable() { |
| | | return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false); |
| | | } |
| | | |
| | | /** |
| | | * å¼å¯å¿½ç¥ç§æ·(å¼å¯åéæå¨è°ç¨ {@link #disableIgnore()} å
³é) |
| | | */ |
| | | public static void enableIgnore() { |
| | | InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build()); |
| | | } |
| | | |
| | | /** |
| | | * å
³é忽ç¥ç§æ· |
| | | */ |
| | | public static void disableIgnore() { |
| | | InterceptorIgnoreHelper.clearIgnoreStrategy(); |
| | | } |
| | | |
| | | /** |
| | | * è®¾ç½®å¨æç§æ·(ä¸ç´ææ éè¦æå¨æ¸
ç) |
| | | * <p> |
| | | * å¦æä¸ºéwebç¯å¢ é£ä¹åªå¨å½å线ç¨å
çæ |
| | | */ |
| | | public static void setDynamic(String tenantId) { |
| | | if (!SpringMVCUtil.isWeb()) { |
| | | TEMP_DYNAMIC_TENANT.set(tenantId); |
| | | return; |
| | | } |
| | | String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); |
| | | RedisUtils.setCacheObject(cacheKey, tenantId); |
| | | SaHolder.getStorage().set(cacheKey, tenantId); |
| | | } |
| | | |
| | | /** |
| | | * è·åå¨æç§æ·(ä¸ç´ææ éè¦æå¨æ¸
ç) |
| | | * <p> |
| | | * å¦æä¸ºéwebç¯å¢ é£ä¹åªå¨å½å线ç¨å
çæ |
| | | */ |
| | | public static String getDynamic() { |
| | | if (!SpringMVCUtil.isWeb()) { |
| | | return TEMP_DYNAMIC_TENANT.get(); |
| | | } |
| | | String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); |
| | | String tenantId = (String) SaHolder.getStorage().get(cacheKey); |
| | | if (StringUtils.isNotBlank(tenantId)) { |
| | | return tenantId; |
| | | } |
| | | tenantId = RedisUtils.getCacheObject(cacheKey); |
| | | SaHolder.getStorage().set(cacheKey, tenantId); |
| | | return tenantId; |
| | | } |
| | | |
| | | /** |
| | | * æ¸
é¤å¨æç§æ· |
| | | */ |
| | | public static void clearDynamic() { |
| | | if (!SpringMVCUtil.isWeb()) { |
| | | TEMP_DYNAMIC_TENANT.remove(); |
| | | return; |
| | | } |
| | | String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); |
| | | RedisUtils.deleteObject(cacheKey); |
| | | SaHolder.getStorage().delete(cacheKey); |
| | | } |
| | | |
| | | /** |
| | | * è·åå½åç§æ·id(å¨æç§æ·ä¼å
) |
| | | */ |
| | | public static String getTenantId() { |
| | | String tenantId = TenantHelper.getDynamic(); |
| | | if (StringUtils.isBlank(tenantId)) { |
| | | tenantId = LoginHelper.getTenantId(); |
| | | } |
| | | return tenantId; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.manager; |
| | | |
| | | import org.dromara.common.core.constant.GlobalConstants; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.redis.manager.PlusSpringCacheManager; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | import org.springframework.cache.Cache; |
| | | |
| | | /** |
| | | * éå cacheName å¤çæ¹æ³ æ¯æå¤ç§æ· |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class TenantSpringCacheManager extends PlusSpringCacheManager { |
| | | |
| | | public TenantSpringCacheManager() { |
| | | } |
| | | |
| | | @Override |
| | | public Cache getCache(String name) { |
| | | if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { |
| | | return super.getCache(name); |
| | | } |
| | | String tenantId = TenantHelper.getTenantId(); |
| | | if (StringUtils.startsWith(name, tenantId)) { |
| | | // 妿åå¨åç´æ¥è¿å |
| | | return super.getCache(name); |
| | | } |
| | | return super.getCache(tenantId + ":" + name); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.tenant.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * ç§æ· é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "tenant") |
| | | public class TenantProperties { |
| | | |
| | | /** |
| | | * æ¯å¦å¯ç¨ |
| | | */ |
| | | private Boolean enable; |
| | | |
| | | /** |
| | | * æé¤è¡¨ |
| | | */ |
| | | private List<String> excludes; |
| | | |
| | | } |
| | |
| | | com.ruoyi.common.tenant.config.TenantConfig |
| | | org.dromara.common.tenant.config.TenantConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | <dependencies> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.annotation; |
| | | |
| | | import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; |
| | | import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
| | | import org.dromara.common.translation.core.handler.TranslationHandler; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * éç¨ç¿»è¯æ³¨è§£ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Inherited |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target({ElementType.FIELD, ElementType.METHOD}) |
| | | @Documented |
| | | @JacksonAnnotationsInside |
| | | @JsonSerialize(using = TranslationHandler.class) |
| | | public @interface Translation { |
| | | |
| | | /** |
| | | * ç±»å (éä¸å®ç°ç±»ä¸ç {@link TranslationType} 注解type对åº) |
| | | * <p> |
| | | * é»è®¤åå½ååæ®µçå¼ å¦æè®¾ç½®äº @{@link Translation#mapper()} ååæ å°å段çå¼ |
| | | */ |
| | | String type(); |
| | | |
| | | /** |
| | | * æ å°å段 (妿ä¸ä¸ºç©ºå忤忮µçå¼) |
| | | */ |
| | | String mapper() default ""; |
| | | |
| | | /** |
| | | * å
¶ä»æ¡ä»¶ ä¾å¦: åå
¸type(sys_user_sex) |
| | | */ |
| | | String other() default ""; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.annotation; |
| | | |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | |
| | | import java.lang.annotation.*; |
| | | |
| | | /** |
| | | * ç¿»è¯ç±»å注解 (æ æ³¨å°{@link TranslationInterface} çå®ç°ç±») |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Inherited |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @Target({ElementType.TYPE}) |
| | | @Documented |
| | | public @interface TranslationType { |
| | | |
| | | /** |
| | | * ç±»å |
| | | */ |
| | | String type(); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.config; |
| | | |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import org.dromara.common.translation.core.handler.TranslationBeanSerializerModifier; |
| | | import org.dromara.common.translation.core.handler.TranslationHandler; |
| | | import jakarta.annotation.PostConstruct; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * ç¿»è¯æ¨¡åé
置类 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @AutoConfiguration |
| | | public class TranslationConfig { |
| | | |
| | | @Autowired |
| | | private List<TranslationInterface<?>> list; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @PostConstruct |
| | | public void init() { |
| | | Map<String, TranslationInterface<?>> map = new HashMap<>(list.size()); |
| | | for (TranslationInterface<?> trans : list) { |
| | | if (trans.getClass().isAnnotationPresent(TranslationType.class)) { |
| | | TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class); |
| | | map.put(annotation.type(), trans); |
| | | } else { |
| | | log.warn(trans.getClass().getName() + " ç¿»è¯å®ç°ç±»æªæ 注 TranslationType 注解!"); |
| | | } |
| | | } |
| | | TranslationHandler.TRANSLATION_MAPPER.putAll(map); |
| | | // 设置 Bean åºååä¿®æ¹å¨ |
| | | objectMapper.setSerializerFactory( |
| | | objectMapper.getSerializerFactory() |
| | | .withSerializerModifier(new TranslationBeanSerializerModifier())); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.constant; |
| | | |
| | | /** |
| | | * ç¿»è¯å¸¸é |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface TransConstant { |
| | | |
| | | /** |
| | | * ç¨æ·idè½¬è´¦å· |
| | | */ |
| | | String USER_ID_TO_NAME = "user_id_to_name"; |
| | | |
| | | /** |
| | | * é¨é¨id转åç§° |
| | | */ |
| | | String DEPT_ID_TO_NAME = "dept_id_to_name"; |
| | | |
| | | /** |
| | | * åå
¸type转label |
| | | */ |
| | | String DICT_TYPE_TO_LABEL = "dict_type_to_label"; |
| | | |
| | | /** |
| | | * ossId转url |
| | | */ |
| | | String OSS_ID_TO_URL = "oss_id_to_url"; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core; |
| | | |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | |
| | | /** |
| | | * ç¿»è¯æ¥å£ (å®ç°ç±»éæ æ³¨ {@link TranslationType} æ³¨è§£æ æç¿»è¯ç±»å) |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface TranslationInterface<T> { |
| | | |
| | | /** |
| | | * ç¿»è¯ |
| | | * |
| | | * @param key éè¦è¢«ç¿»è¯çé®(ä¸ä¸ºç©º) |
| | | * @param other å
¶ä»åæ° |
| | | * @return è¿åé®å¯¹åºçå¼ |
| | | */ |
| | | T translation(Object key, String other); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.handler; |
| | | |
| | | import com.fasterxml.jackson.databind.BeanDescription; |
| | | import com.fasterxml.jackson.databind.SerializationConfig; |
| | | import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; |
| | | import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * Bean åºååä¿®æ¹å¨ è§£å³ Null 被åç¬å¤çé®é¢ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class TranslationBeanSerializerModifier extends BeanSerializerModifier { |
| | | |
| | | @Override |
| | | public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, |
| | | List<BeanPropertyWriter> beanProperties) { |
| | | for (BeanPropertyWriter writer : beanProperties) { |
| | | // 妿åºååå¨ä¸º TranslationHandler çè¯ å° Null å¼ä¹äº¤ç»ä»å¤ç |
| | | if (writer.getSerializer() instanceof TranslationHandler serializer) { |
| | | writer.assignNullSerializer(serializer); |
| | | } |
| | | } |
| | | return beanProperties; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.handler; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.fasterxml.jackson.core.JsonGenerator; |
| | | import com.fasterxml.jackson.databind.BeanProperty; |
| | | import com.fasterxml.jackson.databind.JsonMappingException; |
| | | import com.fasterxml.jackson.databind.JsonSerializer; |
| | | import com.fasterxml.jackson.databind.SerializerProvider; |
| | | import com.fasterxml.jackson.databind.ser.ContextualSerializer; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.core.utils.reflect.ReflectUtils; |
| | | import org.dromara.common.translation.annotation.Translation; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * ç¿»è¯å¤çå¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | public class TranslationHandler extends JsonSerializer<Object> implements ContextualSerializer { |
| | | |
| | | /** |
| | | * å
¨å±ç¿»è¯å®ç°ç±»æ å°å¨ |
| | | */ |
| | | public static final Map<String, TranslationInterface<?>> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); |
| | | |
| | | private Translation translation; |
| | | |
| | | @Override |
| | | public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { |
| | | TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type()); |
| | | if (ObjectUtil.isNotNull(trans)) { |
| | | // 妿æ å°å段ä¸ä¸ºç©º ååæ å°å段çå¼ |
| | | if (StringUtils.isNotBlank(translation.mapper())) { |
| | | value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper()); |
| | | } |
| | | // å¦æä¸º null ç´æ¥ååº |
| | | if (ObjectUtil.isNull(value)) { |
| | | gen.writeNull(); |
| | | return; |
| | | } |
| | | Object result = trans.translation(value, translation.other()); |
| | | gen.writeObject(result); |
| | | } else { |
| | | gen.writeObject(value); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { |
| | | Translation translation = property.getAnnotation(Translation.class); |
| | | if (Objects.nonNull(translation)) { |
| | | this.translation = translation; |
| | | return this; |
| | | } |
| | | return prov.findValueSerializer(property.getType(), property); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.impl; |
| | | |
| | | import org.dromara.common.core.service.DeptService; |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | import org.dromara.common.translation.constant.TransConstant; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import lombok.AllArgsConstructor; |
| | | |
| | | /** |
| | | * é¨é¨ç¿»è¯å®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | @TranslationType(type = TransConstant.DEPT_ID_TO_NAME) |
| | | public class DeptNameTranslationImpl implements TranslationInterface<String> { |
| | | |
| | | private final DeptService deptService; |
| | | |
| | | public String translation(Object key, String other) { |
| | | if (key instanceof String ids) { |
| | | return deptService.selectDeptNameByIds(ids); |
| | | } else if (key instanceof Long id) { |
| | | return deptService.selectDeptNameByIds(id.toString()); |
| | | } |
| | | return null; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.impl; |
| | | |
| | | import org.dromara.common.core.service.DictService; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | import org.dromara.common.translation.constant.TransConstant; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import lombok.AllArgsConstructor; |
| | | |
| | | /** |
| | | * åå
¸ç¿»è¯å®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | @TranslationType(type = TransConstant.DICT_TYPE_TO_LABEL) |
| | | public class DictTypeTranslationImpl implements TranslationInterface<String> { |
| | | |
| | | private final DictService dictService; |
| | | |
| | | public String translation(Object key, String other) { |
| | | if (key instanceof String dictValue && StringUtils.isNotBlank(other)) { |
| | | return dictService.getDictLabel(other, dictValue); |
| | | } |
| | | return null; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.impl; |
| | | |
| | | import org.dromara.common.core.service.OssService; |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | import org.dromara.common.translation.constant.TransConstant; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import lombok.AllArgsConstructor; |
| | | |
| | | /** |
| | | * OSSç¿»è¯å®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | @TranslationType(type = TransConstant.OSS_ID_TO_URL) |
| | | public class OssUrlTranslationImpl implements TranslationInterface<String> { |
| | | |
| | | private final OssService ossService; |
| | | |
| | | public String translation(Object key, String other) { |
| | | if (key instanceof String ids) { |
| | | return ossService.selectUrlByIds(ids); |
| | | } else if (key instanceof Long id) { |
| | | return ossService.selectUrlByIds(id.toString()); |
| | | } |
| | | return null; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.translation.core.impl; |
| | | |
| | | import org.dromara.common.core.service.UserService; |
| | | import org.dromara.common.translation.annotation.TranslationType; |
| | | import org.dromara.common.translation.constant.TransConstant; |
| | | import org.dromara.common.translation.core.TranslationInterface; |
| | | import lombok.AllArgsConstructor; |
| | | |
| | | /** |
| | | * ç¨æ·åç¿»è¯å®ç° |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AllArgsConstructor |
| | | @TranslationType(type = TransConstant.USER_ID_TO_NAME) |
| | | public class UserNameTranslationImpl implements TranslationInterface<String> { |
| | | |
| | | private final UserService userService; |
| | | |
| | | public String translation(Object key, String other) { |
| | | if (key instanceof Long id) { |
| | | return userService.selectUserNameById(id); |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.translation.config.TranslationConfig |
| | | com.ruoyi.common.translation.core.impl.DeptNameTranslationImpl |
| | | com.ruoyi.common.translation.core.impl.DictTypeTranslationImpl |
| | | com.ruoyi.common.translation.core.impl.OssUrlTranslationImpl |
| | | com.ruoyi.common.translation.core.impl.UserNameTranslationImpl |
| | | org.dromara.common.translation.config.TranslationConfig |
| | | org.dromara.common.translation.core.impl.DeptNameTranslationImpl |
| | | org.dromara.common.translation.core.impl.DictTypeTranslationImpl |
| | | org.dromara.common.translation.core.impl.OssUrlTranslationImpl |
| | | org.dromara.common.translation.core.impl.UserNameTranslationImpl |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config; |
| | | |
| | | import cn.hutool.captcha.CaptchaUtil; |
| | | import cn.hutool.captcha.CircleCaptcha; |
| | | import cn.hutool.captcha.LineCaptcha; |
| | | import cn.hutool.captcha.ShearCaptcha; |
| | | import org.dromara.common.web.config.properties.CaptchaProperties; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Lazy; |
| | | |
| | | import java.awt.*; |
| | | |
| | | /** |
| | | * éªè¯ç é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(CaptchaProperties.class) |
| | | public class CaptchaConfig { |
| | | |
| | | private static final int WIDTH = 160; |
| | | private static final int HEIGHT = 60; |
| | | private static final Color BACKGROUND = Color.PINK; |
| | | private static final Font FONT = new Font("Arial", Font.BOLD, 48); |
| | | |
| | | /** |
| | | * ååå¹²æ°éªè¯ç |
| | | */ |
| | | @Lazy |
| | | @Bean |
| | | public CircleCaptcha circleCaptcha() { |
| | | CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT); |
| | | captcha.setBackground(BACKGROUND); |
| | | captcha.setFont(FONT); |
| | | return captcha; |
| | | } |
| | | |
| | | /** |
| | | * 线段干æ°çéªè¯ç |
| | | */ |
| | | @Lazy |
| | | @Bean |
| | | public LineCaptcha lineCaptcha() { |
| | | LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT); |
| | | captcha.setBackground(BACKGROUND); |
| | | captcha.setFont(FONT); |
| | | return captcha; |
| | | } |
| | | |
| | | /** |
| | | * ææ²å¹²æ°éªè¯ç |
| | | */ |
| | | @Lazy |
| | | @Bean |
| | | public ShearCaptcha shearCaptcha() { |
| | | ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT); |
| | | captcha.setBackground(BACKGROUND); |
| | | captcha.setFont(FONT); |
| | | return captcha; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.web.config.properties.XssProperties; |
| | | import org.dromara.common.web.filter.RepeatableFilter; |
| | | import org.dromara.common.web.filter.XssFilter; |
| | | import jakarta.servlet.DispatcherType; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.boot.web.servlet.FilterRegistrationBean; |
| | | import org.springframework.context.annotation.Bean; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Filteré
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | @EnableConfigurationProperties(XssProperties.class) |
| | | public class FilterConfig { |
| | | |
| | | @SuppressWarnings({"rawtypes", "unchecked"}) |
| | | @Bean |
| | | @ConditionalOnProperty(value = "xss.enabled", havingValue = "true") |
| | | public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) { |
| | | FilterRegistrationBean registration = new FilterRegistrationBean(); |
| | | registration.setDispatcherTypes(DispatcherType.REQUEST); |
| | | registration.setFilter(new XssFilter()); |
| | | registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR)); |
| | | registration.setName("xssFilter"); |
| | | registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); |
| | | Map<String, String> initParameters = new HashMap<>(); |
| | | initParameters.put("excludes", xssProperties.getExcludes()); |
| | | registration.setInitParameters(initParameters); |
| | | return registration; |
| | | } |
| | | |
| | | @SuppressWarnings({"rawtypes", "unchecked"}) |
| | | @Bean |
| | | public FilterRegistrationBean someFilterRegistration() { |
| | | FilterRegistrationBean registration = new FilterRegistrationBean(); |
| | | registration.setFilter(new RepeatableFilter()); |
| | | registration.addUrlPatterns("/*"); |
| | | registration.setName("repeatableFilter"); |
| | | registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); |
| | | return registration; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config; |
| | | |
| | | import org.dromara.common.web.core.I18nLocaleResolver; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.web.servlet.LocaleResolver; |
| | | |
| | | /** |
| | | * å½é
åé
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration(before = WebMvcAutoConfiguration.class) |
| | | public class I18nConfig { |
| | | |
| | | @Bean |
| | | public LocaleResolver localeResolver() { |
| | | return new I18nLocaleResolver(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config; |
| | | |
| | | import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.web.cors.CorsConfiguration; |
| | | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
| | | import org.springframework.web.filter.CorsFilter; |
| | | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
| | | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
| | | |
| | | /** |
| | | * éç¨é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | public class ResourcesConfig implements WebMvcConfigurer { |
| | | |
| | | @Override |
| | | public void addInterceptors(InterceptorRegistry registry) { |
| | | // å
¨å±è®¿é®æ§è½æ¦æª |
| | | registry.addInterceptor(new PlusWebInvokeTimeInterceptor()); |
| | | } |
| | | |
| | | @Override |
| | | public void addResourceHandlers(ResourceHandlerRegistry registry) { |
| | | } |
| | | |
| | | /** |
| | | * è·¨åé
ç½® |
| | | */ |
| | | @Bean |
| | | public CorsFilter corsFilter() { |
| | | CorsConfiguration config = new CorsConfiguration(); |
| | | config.setAllowCredentials(true); |
| | | // è®¾ç½®è®¿é®æºå°å |
| | | config.addAllowedOriginPattern("*"); |
| | | // è®¾ç½®è®¿é®æºè¯·æ±å¤´ |
| | | config.addAllowedHeader("*"); |
| | | // è®¾ç½®è®¿é®æºè¯·æ±æ¹æ³ |
| | | config.addAllowedMethod("*"); |
| | | // æææ 1800ç§ |
| | | config.setMaxAge(1800L); |
| | | // æ·»å æ å°è·¯å¾ï¼æ¦æªä¸åè¯·æ± |
| | | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
| | | source.registerCorsConfiguration("/**", config); |
| | | // è¿åæ°çCorsFilter |
| | | return new CorsFilter(source); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config; |
| | | |
| | | import io.undertow.server.DefaultByteBufferPool; |
| | | import io.undertow.websockets.jsr.WebSocketDeploymentInfo; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; |
| | | import org.springframework.boot.web.server.WebServerFactoryCustomizer; |
| | | |
| | | /** |
| | | * Undertow èªå®ä¹é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @AutoConfiguration |
| | | public class UndertowConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> { |
| | | |
| | | /** |
| | | * 设置 Undertow ç websocket ç¼å²æ± |
| | | */ |
| | | @Override |
| | | public void customize(UndertowServletWebServerFactory factory) { |
| | | // é»è®¤ä¸ç´æ¥åé
å
å 妿项ç®ä¸ä½¿ç¨äº websocket å»ºè®®ç´æ¥åé
|
| | | factory.addDeploymentInfoCustomizers(deploymentInfo -> { |
| | | WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); |
| | | webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 512)); |
| | | deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo); |
| | | }); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config.properties; |
| | | |
| | | import org.dromara.common.web.enums.CaptchaCategory; |
| | | import org.dromara.common.web.enums.CaptchaType; |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * éªè¯ç é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "captcha") |
| | | public class CaptchaProperties { |
| | | |
| | | private Boolean enable; |
| | | |
| | | /** |
| | | * éªè¯ç ç±»å |
| | | */ |
| | | private CaptchaType type; |
| | | |
| | | /** |
| | | * éªè¯ç ç±»å« |
| | | */ |
| | | private CaptchaCategory category; |
| | | |
| | | /** |
| | | * æ°åéªè¯ç 使° |
| | | */ |
| | | private Integer numberLength; |
| | | |
| | | /** |
| | | * å符éªè¯ç é¿åº¦ |
| | | */ |
| | | private Integer charLength; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * xssè¿æ»¤ é
ç½®å±æ§ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Data |
| | | @ConfigurationProperties(prefix = "xss") |
| | | public class XssProperties { |
| | | |
| | | /** |
| | | * è¿æ»¤å¼å
³ |
| | | */ |
| | | private String enabled; |
| | | |
| | | /** |
| | | * æé¤é¾æ¥ï¼å¤ä¸ªç¨éå·åéï¼ |
| | | */ |
| | | private String excludes; |
| | | |
| | | /** |
| | | * å¹é
龿¥ |
| | | */ |
| | | private String urlPatterns; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.core; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | |
| | | /** |
| | | * webå±éç¨æ°æ®å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class BaseController { |
| | | |
| | | /** |
| | | * ååºè¿åç»æ |
| | | * |
| | | * @param rows å½±åè¡æ° |
| | | * @return æä½ç»æ |
| | | */ |
| | | protected R<Void> toAjax(int rows) { |
| | | return rows > 0 ? R.ok() : R.fail(); |
| | | } |
| | | |
| | | /** |
| | | * ååºè¿åç»æ |
| | | * |
| | | * @param result ç»æ |
| | | * @return æä½ç»æ |
| | | */ |
| | | protected R<Void> toAjax(boolean result) { |
| | | return result ? R.ok() : R.fail(); |
| | | } |
| | | |
| | | /** |
| | | * 页é¢è·³è½¬ |
| | | */ |
| | | public String redirect(String url) { |
| | | return StringUtils.format("redirect:{}", url); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.core; |
| | | |
| | | import org.springframework.web.servlet.LocaleResolver; |
| | | |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.util.Locale; |
| | | |
| | | /** |
| | | * è·å请æ±å¤´å½é
åä¿¡æ¯ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class I18nLocaleResolver implements LocaleResolver { |
| | | |
| | | @Override |
| | | public Locale resolveLocale(HttpServletRequest httpServletRequest) { |
| | | String language = httpServletRequest.getHeader("content-language"); |
| | | Locale locale = Locale.getDefault(); |
| | | if (language != null && language.length() > 0) { |
| | | String[] split = language.split("_"); |
| | | locale = new Locale(split[0], split[1]); |
| | | } |
| | | return locale; |
| | | } |
| | | |
| | | @Override |
| | | public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.enums; |
| | | |
| | | import cn.hutool.captcha.AbstractCaptcha; |
| | | import cn.hutool.captcha.CircleCaptcha; |
| | | import cn.hutool.captcha.LineCaptcha; |
| | | import cn.hutool.captcha.ShearCaptcha; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * éªè¯ç ç±»å« |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum CaptchaCategory { |
| | | |
| | | /** |
| | | * çº¿æ®µå¹²æ° |
| | | */ |
| | | LINE(LineCaptcha.class), |
| | | |
| | | /** |
| | | * ååå¹²æ° |
| | | */ |
| | | CIRCLE(CircleCaptcha.class), |
| | | |
| | | /** |
| | | * ææ²å¹²æ° |
| | | */ |
| | | SHEAR(ShearCaptcha.class); |
| | | |
| | | private final Class<? extends AbstractCaptcha> clazz; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.enums; |
| | | |
| | | import cn.hutool.captcha.generator.CodeGenerator; |
| | | import cn.hutool.captcha.generator.RandomGenerator; |
| | | import org.dromara.common.web.utils.UnsignedMathGenerator; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * éªè¯ç ç±»å |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum CaptchaType { |
| | | |
| | | /** |
| | | * æ°å |
| | | */ |
| | | MATH(UnsignedMathGenerator.class), |
| | | |
| | | /** |
| | | * å符 |
| | | */ |
| | | CHAR(RandomGenerator.class); |
| | | |
| | | private final Class<? extends CodeGenerator> clazz; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.filter; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.springframework.http.MediaType; |
| | | |
| | | import jakarta.servlet.*; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * Repeatable è¿æ»¤å¨ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class RepeatableFilter implements Filter { |
| | | @Override |
| | | public void init(FilterConfig filterConfig) throws ServletException { |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
| | | throws IOException, ServletException { |
| | | ServletRequest requestWrapper = null; |
| | | if (request instanceof HttpServletRequest |
| | | && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { |
| | | requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); |
| | | } |
| | | if (null == requestWrapper) { |
| | | chain.doFilter(request, response); |
| | | } else { |
| | | chain.doFilter(requestWrapper, response); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void destroy() { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.filter; |
| | | |
| | | import cn.hutool.core.io.IoUtil; |
| | | import org.dromara.common.core.constant.Constants; |
| | | |
| | | import jakarta.servlet.ReadListener; |
| | | import jakarta.servlet.ServletInputStream; |
| | | import jakarta.servlet.ServletResponse; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletRequestWrapper; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | |
| | | /** |
| | | * æå»ºå¯éå¤è¯»åinputStreamçrequest |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { |
| | | private final byte[] body; |
| | | |
| | | public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { |
| | | super(request); |
| | | request.setCharacterEncoding(Constants.UTF8); |
| | | response.setCharacterEncoding(Constants.UTF8); |
| | | |
| | | body = IoUtil.readBytes(request.getInputStream(), false); |
| | | } |
| | | |
| | | @Override |
| | | public BufferedReader getReader() throws IOException { |
| | | return new BufferedReader(new InputStreamReader(getInputStream())); |
| | | } |
| | | |
| | | @Override |
| | | public ServletInputStream getInputStream() throws IOException { |
| | | final ByteArrayInputStream bais = new ByteArrayInputStream(body); |
| | | return new ServletInputStream() { |
| | | @Override |
| | | public int read() throws IOException { |
| | | return bais.read(); |
| | | } |
| | | |
| | | @Override |
| | | public int available() throws IOException { |
| | | return body.length; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isFinished() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isReady() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public void setReadListener(ReadListener readListener) { |
| | | |
| | | } |
| | | }; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.filter; |
| | | |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.springframework.http.HttpMethod; |
| | | |
| | | import jakarta.servlet.*; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 鲿¢XSSæ»å»çè¿æ»¤å¨ |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class XssFilter implements Filter { |
| | | /** |
| | | * æé¤é¾æ¥ |
| | | */ |
| | | public List<String> excludes = new ArrayList<>(); |
| | | |
| | | @Override |
| | | public void init(FilterConfig filterConfig) throws ServletException { |
| | | String tempExcludes = filterConfig.getInitParameter("excludes"); |
| | | if (StringUtils.isNotEmpty(tempExcludes)) { |
| | | String[] url = tempExcludes.split(StringUtils.SEPARATOR); |
| | | for (int i = 0; url != null && i < url.length; i++) { |
| | | excludes.add(url[i]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
| | | throws IOException, ServletException { |
| | | HttpServletRequest req = (HttpServletRequest) request; |
| | | HttpServletResponse resp = (HttpServletResponse) response; |
| | | if (handleExcludeURL(req, resp)) { |
| | | chain.doFilter(request, response); |
| | | return; |
| | | } |
| | | XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); |
| | | chain.doFilter(xssRequest, response); |
| | | } |
| | | |
| | | private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { |
| | | String url = request.getServletPath(); |
| | | String method = request.getMethod(); |
| | | // GET DELETE ä¸è¿æ»¤ |
| | | if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) { |
| | | return true; |
| | | } |
| | | return StringUtils.matches(url, excludes); |
| | | } |
| | | |
| | | @Override |
| | | public void destroy() { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.filter; |
| | | |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.http.HtmlUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.MediaType; |
| | | |
| | | import jakarta.servlet.ReadListener; |
| | | import jakarta.servlet.ServletInputStream; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletRequestWrapper; |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.IOException; |
| | | import java.nio.charset.StandardCharsets; |
| | | |
| | | /** |
| | | * XSSè¿æ»¤å¤ç |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { |
| | | /** |
| | | * @param request |
| | | */ |
| | | public XssHttpServletRequestWrapper(HttpServletRequest request) { |
| | | super(request); |
| | | } |
| | | |
| | | @Override |
| | | public String[] getParameterValues(String name) { |
| | | String[] values = super.getParameterValues(name); |
| | | if (values != null) { |
| | | int length = values.length; |
| | | String[] escapseValues = new String[length]; |
| | | for (int i = 0; i < length; i++) { |
| | | // é²xssæ»å»åè¿æ»¤ååç©ºæ ¼ |
| | | escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim(); |
| | | } |
| | | return escapseValues; |
| | | } |
| | | return super.getParameterValues(name); |
| | | } |
| | | |
| | | @Override |
| | | public ServletInputStream getInputStream() throws IOException { |
| | | // éjsonç±»åï¼ç´æ¥è¿å |
| | | if (!isJsonRequest()) { |
| | | return super.getInputStream(); |
| | | } |
| | | |
| | | // 为空ï¼ç´æ¥è¿å |
| | | String json = StrUtil.str(IoUtil.readBytes(super.getInputStream(), false), StandardCharsets.UTF_8); |
| | | if (StringUtils.isEmpty(json)) { |
| | | return super.getInputStream(); |
| | | } |
| | | |
| | | // xssè¿æ»¤ |
| | | json = HtmlUtil.cleanHtmlTag(json).trim(); |
| | | byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); |
| | | final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes); |
| | | return new ServletInputStream() { |
| | | @Override |
| | | public boolean isFinished() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isReady() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public int available() throws IOException { |
| | | return jsonBytes.length; |
| | | } |
| | | |
| | | @Override |
| | | public void setReadListener(ReadListener readListener) { |
| | | } |
| | | |
| | | @Override |
| | | public int read() throws IOException { |
| | | return bis.read(); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦æ¯Jsonè¯·æ± |
| | | */ |
| | | public boolean isJsonRequest() { |
| | | String header = super.getHeader(HttpHeaders.CONTENT_TYPE); |
| | | return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.interceptor; |
| | | |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.map.MapUtil; |
| | | import com.alibaba.ttl.TransmittableThreadLocal; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.common.web.filter.RepeatedlyRequestWrapper; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.time.StopWatch; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.web.servlet.HandlerInterceptor; |
| | | import org.springframework.web.servlet.ModelAndView; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * webçè°ç¨æ¶é´ç»è®¡æ¦æªå¨ |
| | | * devç¯å¢ææ |
| | | * |
| | | * @author Lion Li |
| | | * @since 3.3.0 |
| | | */ |
| | | @Slf4j |
| | | public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { |
| | | |
| | | private final String prodProfile = "prod"; |
| | | |
| | | private final TransmittableThreadLocal<StopWatch> invokeTimeTL = new TransmittableThreadLocal<>(); |
| | | |
| | | @Override |
| | | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
| | | if (!prodProfile.equals(SpringUtils.getActiveProfile())) { |
| | | String url = request.getMethod() + " " + request.getRequestURI(); |
| | | |
| | | // æå°è¯·æ±åæ° |
| | | if (isJsonRequest(request)) { |
| | | String jsonParam = ""; |
| | | if (request instanceof RepeatedlyRequestWrapper) { |
| | | BufferedReader reader = request.getReader(); |
| | | jsonParam = IoUtil.read(reader); |
| | | } |
| | | log.debug("[PLUS]å¼å§è¯·æ± => URL[{}],åæ°ç±»å[json],åæ°:[{}]", url, jsonParam); |
| | | } else { |
| | | Map<String, String[]> parameterMap = request.getParameterMap(); |
| | | if (MapUtil.isNotEmpty(parameterMap)) { |
| | | String parameters = JsonUtils.toJsonString(parameterMap); |
| | | log.debug("[PLUS]å¼å§è¯·æ± => URL[{}],åæ°ç±»å[param],åæ°:[{}]", url, parameters); |
| | | } else { |
| | | log.debug("[PLUS]å¼å§è¯·æ± => URL[{}],æ åæ°", url); |
| | | } |
| | | } |
| | | |
| | | StopWatch stopWatch = new StopWatch(); |
| | | invokeTimeTL.set(stopWatch); |
| | | stopWatch.start(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { |
| | | if (!prodProfile.equals(SpringUtils.getActiveProfile())) { |
| | | StopWatch stopWatch = invokeTimeTL.get(); |
| | | stopWatch.stop(); |
| | | log.debug("[PLUS]ç»æè¯·æ± => URL[{}],èæ¶:[{}]毫ç§", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime()); |
| | | invokeTimeTL.remove(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å¤ææ¬æ¬¡è¯·æ±çæ°æ®ç±»åæ¯å¦ä¸ºjson |
| | | * |
| | | * @param request request |
| | | * @return boolean |
| | | */ |
| | | private boolean isJsonRequest(HttpServletRequest request) { |
| | | String contentType = request.getContentType(); |
| | | if (contentType != null) { |
| | | return StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.web.utils; |
| | | |
| | | import cn.hutool.captcha.generator.CodeGenerator; |
| | | import cn.hutool.core.math.Calculator; |
| | | import cn.hutool.core.util.CharUtil; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æ 符å·è®¡ç®çæå¨ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public class UnsignedMathGenerator implements CodeGenerator { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = -5514819971774091076L; |
| | | |
| | | private static final String OPERATORS = "+-*"; |
| | | |
| | | /** |
| | | * åä¸è®¡ç®æ°åæå¤§é¿åº¦ |
| | | */ |
| | | private final int numberLength; |
| | | |
| | | /** |
| | | * æé |
| | | */ |
| | | public UnsignedMathGenerator() { |
| | | this(2); |
| | | } |
| | | |
| | | /** |
| | | * æé |
| | | * |
| | | * @param numberLength åä¸è®¡ç®æå¤§æ°å使° |
| | | */ |
| | | public UnsignedMathGenerator(int numberLength) { |
| | | this.numberLength = numberLength; |
| | | } |
| | | |
| | | @Override |
| | | public String generate() { |
| | | final int limit = getLimit(); |
| | | int a = RandomUtil.randomInt(limit); |
| | | int b = RandomUtil.randomInt(limit); |
| | | String max = Integer.toString(Math.max(a,b)); |
| | | String min = Integer.toString(Math.min(a,b)); |
| | | max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE); |
| | | min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE); |
| | | |
| | | return max + RandomUtil.randomChar(OPERATORS) + min + '='; |
| | | } |
| | | |
| | | @Override |
| | | public boolean verify(String code, String userInputCode) { |
| | | int result; |
| | | try { |
| | | result = Integer.parseInt(userInputCode); |
| | | } catch (NumberFormatException e) { |
| | | // ç¨æ·è¾å
¥éæ°å |
| | | return false; |
| | | } |
| | | |
| | | final int calculateResult = (int) Calculator.conversion(code); |
| | | return result == calculateResult; |
| | | } |
| | | |
| | | /** |
| | | * è·åéªè¯ç é¿åº¦ |
| | | * |
| | | * @return éªè¯ç é¿åº¦ |
| | | */ |
| | | public int getLength() { |
| | | return this.numberLength * 2 + 2; |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®é¿åº¦è·ååä¸è®¡ç®æ°åæå¤§å¼ |
| | | * |
| | | * @return æå¤§å¼ |
| | | */ |
| | | private int getLimit() { |
| | | return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength)); |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.web.config.CaptchaConfig |
| | | com.ruoyi.common.web.config.FilterConfig |
| | | com.ruoyi.common.web.config.I18nConfig |
| | | com.ruoyi.common.web.config.ResourcesConfig |
| | | com.ruoyi.common.web.config.UndertowConfig |
| | | org.dromara.common.web.config.CaptchaConfig |
| | | org.dromara.common.web.config.FilterConfig |
| | | org.dromara.common.web.config.I18nConfig |
| | | org.dromara.common.web.config.ResourcesConfig |
| | | org.dromara.common.web.config.UndertowConfig |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-satoken</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-json</artifactId> |
| | | </dependency> |
| | | <dependency> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.config; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import org.dromara.common.websocket.config.properties.WebSocketProperties; |
| | | import org.dromara.common.websocket.handler.PlusWebSocketHandler; |
| | | import org.dromara.common.websocket.interceptor.PlusWebSocketInterceptor; |
| | | import org.dromara.common.websocket.listener.WebSocketTopicListener; |
| | | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.web.socket.WebSocketHandler; |
| | | import org.springframework.web.socket.config.annotation.EnableWebSocket; |
| | | import org.springframework.web.socket.config.annotation.WebSocketConfigurer; |
| | | import org.springframework.web.socket.server.HandshakeInterceptor; |
| | | |
| | | /** |
| | | * WebSocket é
ç½® |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @AutoConfiguration |
| | | @ConditionalOnProperty(value = "websocket.enabled", havingValue = "true") |
| | | @EnableConfigurationProperties(WebSocketProperties.class) |
| | | @EnableWebSocket |
| | | public class WebSocketConfig { |
| | | |
| | | @Bean |
| | | public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor, |
| | | WebSocketHandler webSocketHandler, |
| | | WebSocketProperties webSocketProperties) { |
| | | if (StrUtil.isBlank(webSocketProperties.getPath())) { |
| | | webSocketProperties.setPath("/websocket"); |
| | | } |
| | | |
| | | if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) { |
| | | webSocketProperties.setAllowedOrigins("*"); |
| | | } |
| | | |
| | | return registry -> registry |
| | | .addHandler(webSocketHandler, webSocketProperties.getPath()) |
| | | .addInterceptors(handshakeInterceptor) |
| | | .setAllowedOrigins(webSocketProperties.getAllowedOrigins()); |
| | | } |
| | | |
| | | @Bean |
| | | public HandshakeInterceptor handshakeInterceptor() { |
| | | return new PlusWebSocketInterceptor(); |
| | | } |
| | | |
| | | @Bean |
| | | public WebSocketHandler webSocketHandler() { |
| | | return new PlusWebSocketHandler(); |
| | | } |
| | | |
| | | @Bean |
| | | public WebSocketTopicListener topicListener() { |
| | | return new WebSocketTopicListener(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.config.properties; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * WebSocket é
置项 |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @ConfigurationProperties("websocket") |
| | | @Data |
| | | public class WebSocketProperties { |
| | | |
| | | private Boolean enabled; |
| | | |
| | | /** |
| | | * è·¯å¾ |
| | | */ |
| | | private String path; |
| | | |
| | | /** |
| | | * è®¾ç½®è®¿é®æºå°å |
| | | */ |
| | | private String allowedOrigins; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.constant; |
| | | |
| | | /** |
| | | * websocketç常éé
ç½® |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | public interface WebSocketConstants { |
| | | /** |
| | | * websocketSessionä¸çåæ°çkey |
| | | */ |
| | | String LOGIN_USER_KEY = "loginUser"; |
| | | |
| | | /** |
| | | * 订é
çé¢é |
| | | */ |
| | | String WEB_SOCKET_TOPIC = "global:websocket"; |
| | | |
| | | /** |
| | | * å端å¿è·³æ£æ¥çå½ä»¤ |
| | | */ |
| | | String PING = "ping"; |
| | | |
| | | /** |
| | | * æå¡ç«¯å¿è·³æ¢å¤çå符串 |
| | | */ |
| | | String PONG = "pong"; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ¶æ¯çdto |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @Data |
| | | public class WebSocketMessageDto implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * éè¦æ¨éå°çsession key å表 |
| | | */ |
| | | private List<Long> sessionKeys; |
| | | |
| | | /** |
| | | * éè¦åéçæ¶æ¯ |
| | | */ |
| | | private String message; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.handler; |
| | | |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.websocket.dto.WebSocketMessageDto; |
| | | import org.dromara.common.websocket.holder.WebSocketSessionHolder; |
| | | import org.dromara.common.websocket.utils.WebSocketUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.socket.*; |
| | | import org.springframework.web.socket.handler.AbstractWebSocketHandler; |
| | | |
| | | import java.util.List; |
| | | |
| | | import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; |
| | | |
| | | /** |
| | | * WebSocketHandler å®ç°ç±» |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @Slf4j |
| | | public class PlusWebSocketHandler extends AbstractWebSocketHandler { |
| | | |
| | | /** |
| | | * è¿æ¥æåå |
| | | */ |
| | | @Override |
| | | public void afterConnectionEstablished(WebSocketSession session) { |
| | | LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); |
| | | WebSocketSessionHolder.addSession(loginUser.getUserId(), session); |
| | | log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); |
| | | } |
| | | |
| | | /** |
| | | * å¤çåéæ¥çææ¬æ¶æ¯ |
| | | * |
| | | * @param session |
| | | * @param message |
| | | * @throws Exception |
| | | */ |
| | | @Override |
| | | protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { |
| | | LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); |
| | | log.info("PlusWebSocketHandler, è¿æ¥ï¼" + session.getId() + "ï¼å·²æ¶å°æ¶æ¯:" + message.getPayload()); |
| | | List<Long> userIds = List.of(loginUser.getUserId()); |
| | | WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto(); |
| | | webSocketMessageDto.setSessionKeys(userIds); |
| | | webSocketMessageDto.setMessage(message.getPayload()); |
| | | WebSocketUtils.publishMessage(webSocketMessageDto); |
| | | } |
| | | |
| | | @Override |
| | | protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception { |
| | | super.handleBinaryMessage(session, message); |
| | | } |
| | | |
| | | /** |
| | | * å¿è·³çæµçåå¤ |
| | | * |
| | | * @param session |
| | | * @param message |
| | | * @throws Exception |
| | | */ |
| | | @Override |
| | | protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception { |
| | | WebSocketUtils.sendPongMessage(session); |
| | | } |
| | | |
| | | /** |
| | | * è¿æ¥åºéæ¶ |
| | | * |
| | | * @param session |
| | | * @param exception |
| | | * @throws Exception |
| | | */ |
| | | @Override |
| | | public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { |
| | | log.error("[transport error] sessionId: {} , exception:{}", session.getId(), exception.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * è¿æ¥å
³éå |
| | | * |
| | | * @param session |
| | | * @param status |
| | | */ |
| | | @Override |
| | | public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { |
| | | LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); |
| | | WebSocketSessionHolder.removeSession(loginUser.getUserId()); |
| | | log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦æ¯æåçæ¶æ¯ |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public boolean supportsPartialMessages() { |
| | | return false; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.holder; |
| | | |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.springframework.web.socket.WebSocketSession; |
| | | |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * WebSocketSession ç¨äºä¿åå½åææå¨çº¿çä¼è¯ä¿¡æ¯ |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class WebSocketSessionHolder { |
| | | |
| | | private static final Map<Long, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>(); |
| | | |
| | | public static void addSession(Long sessionKey, WebSocketSession session) { |
| | | USER_SESSION_MAP.put(sessionKey, session); |
| | | } |
| | | |
| | | public static void removeSession(Long sessionKey) { |
| | | if (USER_SESSION_MAP.containsKey(sessionKey)) { |
| | | USER_SESSION_MAP.remove(sessionKey); |
| | | } |
| | | } |
| | | |
| | | public static WebSocketSession getSessions(Long sessionKey) { |
| | | return USER_SESSION_MAP.get(sessionKey); |
| | | } |
| | | |
| | | public static Boolean existSession(Long sessionKey) { |
| | | return USER_SESSION_MAP.containsKey(sessionKey); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.interceptor; |
| | | |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.satoken.utils.LoginHelper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.http.server.ServerHttpRequest; |
| | | import org.springframework.http.server.ServerHttpResponse; |
| | | import org.springframework.web.socket.WebSocketHandler; |
| | | import org.springframework.web.socket.server.HandshakeInterceptor; |
| | | |
| | | import java.util.Map; |
| | | |
| | | import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; |
| | | |
| | | /** |
| | | * WebSocketæ¡æè¯·æ±çæ¦æªå¨ |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @Slf4j |
| | | public class PlusWebSocketInterceptor implements HandshakeInterceptor { |
| | | |
| | | /** |
| | | * æ¡æå |
| | | * |
| | | * @param request request |
| | | * @param response response |
| | | * @param wsHandler wsHandler |
| | | * @param attributes attributes |
| | | * @return æ¯å¦æ¡ææå |
| | | */ |
| | | @Override |
| | | public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) { |
| | | LoginUser loginUser = LoginHelper.getLoginUser(); |
| | | attributes.put(LOGIN_USER_KEY, loginUser); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * æ¡æå |
| | | * |
| | | * @param request request |
| | | * @param response response |
| | | * @param wsHandler wsHandler |
| | | * @param exception å¼å¸¸ |
| | | */ |
| | | @Override |
| | | public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.listener; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import org.dromara.common.websocket.holder.WebSocketSessionHolder; |
| | | import org.dromara.common.websocket.utils.WebSocketUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.boot.ApplicationArguments; |
| | | import org.springframework.boot.ApplicationRunner; |
| | | import org.springframework.core.Ordered; |
| | | |
| | | /** |
| | | * WebSocket 主é¢è®¢é
çå¬å¨ |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @Slf4j |
| | | public class WebSocketTopicListener implements ApplicationRunner, Ordered { |
| | | |
| | | @Override |
| | | public void run(ApplicationArguments args) throws Exception { |
| | | WebSocketUtils.subscribeMessage((message) -> { |
| | | log.info("WebSocket主é¢è®¢é
æ¶å°æ¶æ¯session keys={} message={}ï¼", message.getSessionKeys(), message.getMessage()); |
| | | if (CollUtil.isNotEmpty(message.getSessionKeys())) { |
| | | message.getSessionKeys().forEach(key -> { |
| | | if (WebSocketSessionHolder.existSession(key)) { |
| | | WebSocketUtils.sendMessage(key, message.getMessage()); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | log.info("åå§åWebSocket主é¢è®¢é
çå¬å¨æå"); |
| | | } |
| | | |
| | | @Override |
| | | public int getOrder() { |
| | | return -1; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.common.websocket.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import org.dromara.common.core.domain.model.LoginUser; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.dromara.common.websocket.dto.WebSocketMessageDto; |
| | | import org.dromara.common.websocket.holder.WebSocketSessionHolder; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.socket.PongMessage; |
| | | import org.springframework.web.socket.TextMessage; |
| | | import org.springframework.web.socket.WebSocketMessage; |
| | | import org.springframework.web.socket.WebSocketSession; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.function.Consumer; |
| | | |
| | | import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; |
| | | import static org.dromara.common.websocket.constant.WebSocketConstants.WEB_SOCKET_TOPIC; |
| | | |
| | | /** |
| | | * å·¥å
·ç±» |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @Slf4j |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class WebSocketUtils { |
| | | |
| | | /** |
| | | * åéæ¶æ¯ |
| | | * |
| | | * @param sessionKey sessionä¸»é® ä¸è¬ä¸ºç¨æ·id |
| | | * @param message æ¶æ¯ææ¬ |
| | | */ |
| | | public static void sendMessage(Long sessionKey, String message) { |
| | | WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey); |
| | | sendMessage(session, message); |
| | | } |
| | | |
| | | /** |
| | | * 订é
æ¶æ¯ |
| | | * |
| | | * @param consumer èªå®ä¹å¤ç |
| | | */ |
| | | public static void subscribeMessage(Consumer<WebSocketMessageDto> consumer) { |
| | | RedisUtils.subscribe(WEB_SOCKET_TOPIC, WebSocketMessageDto.class, consumer); |
| | | } |
| | | |
| | | /** |
| | | * åå¸è®¢é
çæ¶æ¯ |
| | | * |
| | | * @param webSocketMessage æ¶æ¯å¯¹è±¡ |
| | | */ |
| | | public static void publishMessage(WebSocketMessageDto webSocketMessage) { |
| | | List<Long> unsentSessionKeys = new ArrayList<>(); |
| | | // å½åæå¡å
session,ç´æ¥åéæ¶æ¯ |
| | | for (Long sessionKey : webSocketMessage.getSessionKeys()) { |
| | | if (WebSocketSessionHolder.existSession(sessionKey)) { |
| | | WebSocketUtils.sendMessage(sessionKey, webSocketMessage.getMessage()); |
| | | continue; |
| | | } |
| | | unsentSessionKeys.add(sessionKey); |
| | | } |
| | | // ä¸å¨å½åæå¡å
session,åå¸è®¢é
æ¶æ¯ |
| | | if (CollUtil.isNotEmpty(unsentSessionKeys)) { |
| | | WebSocketMessageDto broadcastMessage = new WebSocketMessageDto(); |
| | | broadcastMessage.setMessage(webSocketMessage.getMessage()); |
| | | broadcastMessage.setSessionKeys(unsentSessionKeys); |
| | | RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> { |
| | | log.info(" WebSocketåé主é¢è®¢é
æ¶æ¯topic:{} session keys:{} message:{}", |
| | | WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage()); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | public static void sendPongMessage(WebSocketSession session) { |
| | | sendMessage(session, new PongMessage()); |
| | | } |
| | | |
| | | public static void sendMessage(WebSocketSession session, String message) { |
| | | sendMessage(session, new TextMessage(message)); |
| | | } |
| | | |
| | | private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) { |
| | | if (session == null || !session.isOpen()) { |
| | | log.error("[send] sessionä¼è¯å·²ç»å
³é"); |
| | | } else { |
| | | try { |
| | | // è·åå½åä¼è¯ä¸çç¨æ· |
| | | LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); |
| | | session.sendMessage(message); |
| | | log.info("[send] sessionId: {},userId:{},userType:{},message:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType(), message); |
| | | } catch (IOException e) { |
| | | log.error("[send] session({}) åéæ¶æ¯({}) å¼å¸¸", session, message, e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | com.ruoyi.common.websocket.config.WebSocketConfig |
| | | org.dromara.common.websocket.config.WebSocketConfig |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <artifactId>ruoyi-vue-plus</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <artifactId>ruoyi-extend</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.monitor.admin; |
| | | |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | | |
| | | /** |
| | | * Admin çæ§å¯å¨ç¨åº |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @SpringBootApplication |
| | | public class MonitorAdminApplication { |
| | | |
| | | public static void main(String[] args) { |
| | | SpringApplication.run(MonitorAdminApplication.class, args); |
| | | System.out.println("Admin çæ§å¯å¨æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.monitor.admin.config; |
| | | |
| | | import de.codecentric.boot.admin.server.config.EnableAdminServer; |
| | | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
| | | import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; |
| | | import org.springframework.boot.task.TaskExecutorBuilder; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | |
| | | import java.util.concurrent.Executor; |
| | | |
| | | /** |
| | | * springboot-admin serveré
置类 |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Configuration |
| | | @EnableAdminServer |
| | | public class AdminServerConfig { |
| | | |
| | | @Lazy |
| | | @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) |
| | | @ConditionalOnMissingBean(Executor.class) |
| | | public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { |
| | | return builder.build(); |
| | | } |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.monitor.admin.config; |
| | | |
| | | import de.codecentric.boot.admin.server.config.AdminServerProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
| | | import org.springframework.security.web.SecurityFilterChain; |
| | | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; |
| | | |
| | | /** |
| | | * admin çæ§ å®å
¨é
ç½® |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @EnableWebSecurity |
| | | @Configuration |
| | | public class SecurityConfig { |
| | | |
| | | private final String adminContextPath; |
| | | |
| | | public SecurityConfig(AdminServerProperties adminServerProperties) { |
| | | this.adminContextPath = adminServerProperties.getContextPath(); |
| | | } |
| | | |
| | | @Bean |
| | | public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { |
| | | SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); |
| | | successHandler.setTargetUrlParameter("redirectTo"); |
| | | successHandler.setDefaultTargetUrl(adminContextPath + "/"); |
| | | |
| | | return httpSecurity |
| | | .headers().frameOptions().disable() |
| | | .and().authorizeHttpRequests() |
| | | .requestMatchers(adminContextPath + "/assets/**" |
| | | , adminContextPath + "/login" |
| | | , "/actuator" |
| | | , "/actuator/**" |
| | | ).permitAll() |
| | | .anyRequest().authenticated() |
| | | .and() |
| | | .formLogin().loginPage(adminContextPath + "/login") |
| | | .successHandler(successHandler).and() |
| | | .logout().logoutUrl(adminContextPath + "/logout") |
| | | .and() |
| | | .httpBasic().and() |
| | | .csrf() |
| | | .disable() |
| | | .build(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.monitor.admin.notifier; |
| | | |
| | | import de.codecentric.boot.admin.server.domain.entities.Instance; |
| | | import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; |
| | | import de.codecentric.boot.admin.server.domain.events.InstanceEvent; |
| | | import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; |
| | | import de.codecentric.boot.admin.server.notify.AbstractEventNotifier; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | import reactor.core.publisher.Mono; |
| | | |
| | | /** |
| | | * èªå®ä¹äºä»¶éç¥å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class CustomNotifier extends AbstractEventNotifier { |
| | | |
| | | protected CustomNotifier(InstanceRepository repository) { |
| | | super(repository); |
| | | } |
| | | |
| | | @Override |
| | | @SuppressWarnings("all") |
| | | protected Mono<Void> doNotify(InstanceEvent event, Instance instance) { |
| | | return Mono.fromRunnable(() -> { |
| | | // å®ä¾ç¶ææ¹åäºä»¶ |
| | | if (event instanceof InstanceStatusChangedEvent) { |
| | | String registName = instance.getRegistration().getName(); |
| | | String instanceId = event.getInstance().getValue(); |
| | | String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); |
| | | log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status); |
| | | } |
| | | |
| | | }); |
| | | } |
| | | |
| | | } |
| | |
| | | <modelVersion>4.0.0</modelVersion> |
| | | <parent> |
| | | <artifactId>ruoyi-extend</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <artifactId>ruoyi-vue-plus</artifactId> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | | </parent> |
| | |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-modules</artifactId> |
| | | <version>${revision}</version> |
| | | <relativePath>../pom.xml</relativePath> |
| | |
| | | |
| | | <!-- éç¨å·¥å
·--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-doc</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-sms</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-mail</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-redis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-idempotent</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-log</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-excel</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-web</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-ratelimiter</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-translation</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-sensitive</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-encrypt</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-tenant</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <groupId>org.dromara</groupId> |
| | | <artifactId>ruoyi-common-websocket</artifactId> |
| | | </dependency> |
| | | <!-- çä¿¡ ç¨åªä¸ªå¯¼å
¥åªä¸ªä¾èµ --> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.mail.utils.MailUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.io.File; |
| | | |
| | | |
| | | /** |
| | | * é®ä»¶åéæ¡ä¾ |
| | | * |
| | | * @author Michelle.Chung |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/mail") |
| | | public class MailController { |
| | | |
| | | /** |
| | | * åéé®ä»¶ |
| | | * |
| | | * @param to æ¥æ¶äºº |
| | | * @param subject æ é¢ |
| | | * @param text å
容 |
| | | */ |
| | | @GetMapping("/sendSimpleMessage") |
| | | public R<Void> sendSimpleMessage(String to, String subject, String text) { |
| | | MailUtils.sendText(to, subject, text); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * åéé®ä»¶ï¼å¸¦éä»¶ï¼ |
| | | * |
| | | * @param to æ¥æ¶äºº |
| | | * @param subject æ é¢ |
| | | * @param text å
容 |
| | | * @param filePath éä»¶è·¯å¾ |
| | | */ |
| | | @GetMapping("/sendMessageWithAttachment") |
| | | public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) { |
| | | MailUtils.sendText(to, subject, text, new File(filePath)); |
| | | return R.ok(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.constant.CacheNames; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.cache.annotation.CacheEvict; |
| | | import org.springframework.cache.annotation.CachePut; |
| | | import org.springframework.cache.annotation.Cacheable; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.time.Duration; |
| | | |
| | | /** |
| | | * spring-cache æ¼ç¤ºæ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | // ç±»çº§å« ç¼åç»ä¸é
ç½® |
| | | //@CacheConfig(cacheNames = CacheNames.DEMO_CACHE) |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/cache") |
| | | public class RedisCacheController { |
| | | |
| | | /** |
| | | * æµè¯ @Cacheable |
| | | * <p> |
| | | * 表示è¿ä¸ªæ¹æ³æäºç¼åçåè½,æ¹æ³çè¿åå¼ä¼è¢«ç¼å䏿¥ |
| | | * ä¸ä¸æ¬¡è°ç¨è¯¥æ¹æ³å,ä¼å»æ£æ¥æ¯å¦ç¼åä¸å·²ç»æå¼ |
| | | * 妿æå°±ç´æ¥è¿å,ä¸è°ç¨æ¹æ³ |
| | | * å¦ææ²¡æ,å°±è°ç¨æ¹æ³,ç¶åæç»æç¼åèµ·æ¥ |
| | | * è¿ä¸ªæ³¨è§£ãä¸è¬ç¨å¨æ¥è¯¢æ¹æ³ä¸ã |
| | | * <p> |
| | | * éç¹è¯´æ: ç¼å注解严谨ä¸å
¶ä»çéæ°æ®åè½ä¸èµ·ä½¿ç¨ |
| | | * ä¾å¦: æ°æ®æé注解 ä¼é æ ç¼åå»ç©¿ ä¸ æ°æ®ä¸ä¸è´é®é¢ |
| | | * <p> |
| | | * cacheNames å½åè§å æ¥ç {@link CacheNames} æ³¨é æ¯æå¤åæ° |
| | | */ |
| | | @Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null") |
| | | @GetMapping("/test1") |
| | | public R<String> test1(String key, String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯ @CachePut |
| | | * <p> |
| | | * å äº@CachePutæ³¨è§£çæ¹æ³,ä¼ææ¹æ³çè¿åå¼putå°ç¼åéé¢ç¼åèµ·æ¥,ä¾å
¶å®å°æ¹ä½¿ç¨ |
| | | * å®ãé常ç¨å¨æ°å¢æè
宿¶æ´æ°æ¹æ³ä¸ã |
| | | * <p> |
| | | * cacheNames å½åè§å æ¥ç {@link CacheNames} æ³¨é æ¯æå¤åæ° |
| | | */ |
| | | @CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") |
| | | @GetMapping("/test2") |
| | | public R<String> test2(String key, String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯ @CacheEvict |
| | | * <p> |
| | | * 使ç¨äºCacheEvictæ³¨è§£çæ¹æ³,伿¸
空æå®ç¼å |
| | | * ãä¸è¬ç¨å¨å é¤çæ¹æ³ä¸ã |
| | | * <p> |
| | | * cacheNames å½åè§å æ¥ç {@link CacheNames} æ³¨é æ¯æå¤åæ° |
| | | */ |
| | | @CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") |
| | | @GetMapping("/test3") |
| | | public R<String> test3(String key, String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯è®¾ç½®è¿ææ¶é´ |
| | | * æå¨è®¾ç½®è¿ææ¶é´10ç§ |
| | | * 11ç§åè·å 夿æ¯å¦ç¸ç |
| | | */ |
| | | @GetMapping("/test6") |
| | | public R<Boolean> test6(String key, String value) { |
| | | RedisUtils.setCacheObject(key, value); |
| | | boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10)); |
| | | System.out.println("***********" + flag); |
| | | try { |
| | | Thread.sleep(11 * 1000); |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | Object obj = RedisUtils.getCacheObject(key); |
| | | return R.ok(value.equals(obj)); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import com.baomidou.lock.LockInfo; |
| | | import com.baomidou.lock.LockTemplate; |
| | | import com.baomidou.lock.annotation.Lock4j; |
| | | import com.baomidou.lock.executor.RedissonLockExecutor; |
| | | import org.dromara.common.core.domain.R; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.time.LocalTime; |
| | | |
| | | |
| | | /** |
| | | * æµè¯åå¸å¼éçæ ·ä¾ |
| | | * |
| | | * @author shenxinquan |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/demo/redisLock") |
| | | public class RedisLockController { |
| | | |
| | | @Autowired |
| | | private LockTemplate lockTemplate; |
| | | |
| | | /** |
| | | * æµè¯lock4j 注解 |
| | | */ |
| | | @Lock4j(keys = {"#key"}) |
| | | @GetMapping("/testLock4j") |
| | | public R<String> testLock4j(String key, String value) { |
| | | System.out.println("start:" + key + ",time:" + LocalTime.now().toString()); |
| | | try { |
| | | Thread.sleep(10000); |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | System.out.println("end :" + key + ",time:" + LocalTime.now().toString()); |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯lock4j å·¥å
· |
| | | */ |
| | | @GetMapping("/testLock4jLockTemplate") |
| | | public R<String> testLock4jLockTemplate(String key, String value) { |
| | | final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class); |
| | | if (null == lockInfo) { |
| | | throw new RuntimeException("ä¸å¡å¤çä¸,请ç¨ååè¯"); |
| | | } |
| | | // è·åéæåï¼å¤çä¸å¡ |
| | | try { |
| | | try { |
| | | Thread.sleep(8000); |
| | | } catch (InterruptedException e) { |
| | | // |
| | | } |
| | | System.out.println("æ§è¡ç®åæ¹æ³1 , å½å线ç¨:" + Thread.currentThread().getName()); |
| | | } finally { |
| | | //éæ¾é |
| | | lockTemplate.releaseLock(lockInfo); |
| | | } |
| | | //ç»æ |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * Redis åå¸è®¢é
æ¼ç¤ºæ¡ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/redis/pubsub") |
| | | public class RedisPubSubController { |
| | | |
| | | /** |
| | | * å叿¶æ¯ |
| | | * |
| | | * @param key ééKey |
| | | * @param value åéå
容 |
| | | */ |
| | | @GetMapping("/pub") |
| | | public R<Void> pub(String key, String value) { |
| | | RedisUtils.publish(key, value, consumer -> { |
| | | System.out.println("åå¸éé => " + key + ", åéå¼ => " + value); |
| | | }); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * 订é
æ¶æ¯ |
| | | * |
| | | * @param key ééKey |
| | | */ |
| | | @GetMapping("/sub") |
| | | public R<Void> sub(String key) { |
| | | RedisUtils.subscribe(key, String.class, msg -> { |
| | | System.out.println("订é
éé => " + key + ", æ¥æ¶å¼ => " + msg); |
| | | }); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.ratelimiter.annotation.RateLimiter; |
| | | import org.dromara.common.ratelimiter.enums.LimitType; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | |
| | | /** |
| | | * æµè¯åå¸å¼éæµæ ·ä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("/demo/rateLimiter") |
| | | public class RedisRateLimiterController { |
| | | |
| | | /** |
| | | * æµè¯å
¨å±éæµ |
| | | * å
¨å±å½±å |
| | | */ |
| | | @RateLimiter(count = 2, time = 10) |
| | | @GetMapping("/test") |
| | | public R<String> test(String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯è¯·æ±IPéæµ |
| | | * åä¸IP请æ±åå½±å |
| | | */ |
| | | @RateLimiter(count = 2, time = 10, limitType = LimitType.IP) |
| | | @GetMapping("/testip") |
| | | public R<String> testip(String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | /** |
| | | * æµè¯é群å®ä¾éæµ |
| | | * å¯å¨ä¸¤ä¸ªå端æå¡äºä¸å½±å |
| | | */ |
| | | @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER) |
| | | @GetMapping("/testcluster") |
| | | public R<String> testcluster(String value) { |
| | | return R.ok("æä½æå", value); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.sms.config.properties.SmsProperties; |
| | | import org.dromara.common.sms.core.SmsTemplate; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * çä¿¡æ¼ç¤ºæ¡ä¾ |
| | | * 请å
é
è¯»ææ¡£ å¦åæ æ³ä½¿ç¨ |
| | | * |
| | | * @author Lion Li |
| | | * @version 4.2.0 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/sms") |
| | | public class SmsController { |
| | | |
| | | private final SmsProperties smsProperties; |
| | | // private final SmsTemplate smsTemplate; // å¯ä»¥ä½¿ç¨spring注å
¥ |
| | | // private final AliyunSmsTemplate smsTemplate; // ä¹å¯ä»¥æ³¨å
¥æä¸ªåå®¶çæ¨¡æ¿å·¥å
· |
| | | |
| | | /** |
| | | * åéçä¿¡Aliyun |
| | | * |
| | | * @param phones çµè¯å· |
| | | * @param templateId 模æ¿ID |
| | | */ |
| | | @GetMapping("/sendAliyun") |
| | | public R<Object> sendAliyun(String phones, String templateId) { |
| | | if (!smsProperties.getEnabled()) { |
| | | return R.fail("å½åç³»ç»æ²¡æå¼å¯çä¿¡åè½ï¼"); |
| | | } |
| | | if (!SpringUtils.containsBean("aliyunSmsTemplate")) { |
| | | return R.fail("é¿éäºä¾èµæªå¼å
¥ï¼"); |
| | | } |
| | | SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); |
| | | Map<String, String> map = new HashMap<>(1); |
| | | map.put("code", "1234"); |
| | | Object send = smsTemplate.send(phones, templateId, map); |
| | | return R.ok(send); |
| | | } |
| | | |
| | | /** |
| | | * åéçä¿¡Tencent |
| | | * |
| | | * @param phones çµè¯å· |
| | | * @param templateId 模æ¿ID |
| | | */ |
| | | @GetMapping("/sendTencent") |
| | | public R<Object> sendTencent(String phones, String templateId) { |
| | | if (!smsProperties.getEnabled()) { |
| | | return R.fail("å½åç³»ç»æ²¡æå¼å¯çä¿¡åè½ï¼"); |
| | | } |
| | | if (!SpringUtils.containsBean("tencentSmsTemplate")) { |
| | | return R.fail("è
¾è®¯äºä¾èµæªå¼å
¥ï¼"); |
| | | } |
| | | SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); |
| | | Map<String, String> map = new HashMap<>(1); |
| | | // map.put("2", "æµè¯æµè¯"); |
| | | map.put("1", "1234"); |
| | | Object send = smsTemplate.send(phones, templateId, map); |
| | | return R.ok(send); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestPart; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | /** |
| | | * swagger3 ç¨æ³ç¤ºä¾ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/swagger/demo") |
| | | public class Swagger3DemoController { |
| | | |
| | | /** |
| | | * ä¸ä¼ è¯·æ± |
| | | * å¿
é¡»ä½¿ç¨ @RequestPart æ³¨è§£æ æ³¨ä¸ºæä»¶ |
| | | * |
| | | * @param file æä»¶ |
| | | */ |
| | | @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
| | | public R<String> upload(@RequestPart("file") MultipartFile file) { |
| | | return R.ok("æä½æå", file.getOriginalFilename()); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.web.core.BaseController; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import org.dromara.demo.mapper.TestDemoMapper; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æµè¯æ¹éæ¹æ³ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-05-30 |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/batch") |
| | | public class TestBatchController extends BaseController { |
| | | |
| | | /** |
| | | * 为äºä¾¿äºæµè¯ ç´æ¥å¼å
¥mapper |
| | | */ |
| | | private final TestDemoMapper testDemoMapper; |
| | | |
| | | /** |
| | | * æ°å¢æ¹éæ¹æ³ å¯å®ç¾æ¿ä»£ saveBatch ç§çº§æå
¥ä¸ä¸æ°æ® (对mysqlè´è·è¾å¤§) |
| | | * <p> |
| | | * 3.5.0 çæ¬ å¢å rewriteBatchedStatements=true æ¹å¤çåæ° 使 MP åçæ¹å¤çå¯ä»¥è¾¾å°åæ ·çé度 |
| | | */ |
| | | @PostMapping("/add") |
| | | // @DS("slave") |
| | | public R<Void> add() { |
| | | List<TestDemo> list = new ArrayList<>(); |
| | | for (int i = 0; i < 1000; i++) { |
| | | TestDemo testDemo = new TestDemo(); |
| | | testDemo.setOrderNum(-1); |
| | | testDemo.setTestKey("æ¹éæ°å¢"); |
| | | testDemo.setValue("æµè¯æ°å¢"); |
| | | list.add(testDemo); |
| | | } |
| | | return toAjax(testDemoMapper.insertBatch(list)); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢ææ´æ° å¯å®ç¾æ¿ä»£ saveOrUpdateBatch 髿§è½ |
| | | * <p> |
| | | * 3.5.0 çæ¬ å¢å rewriteBatchedStatements=true æ¹å¤çåæ° 使 MP åçæ¹å¤çå¯ä»¥è¾¾å°åæ ·çé度 |
| | | */ |
| | | @PostMapping("/addOrUpdate") |
| | | // @DS("slave") |
| | | public R<Void> addOrUpdate() { |
| | | List<TestDemo> list = new ArrayList<>(); |
| | | for (int i = 0; i < 1000; i++) { |
| | | TestDemo testDemo = new TestDemo(); |
| | | testDemo.setOrderNum(-1); |
| | | testDemo.setTestKey("æ¹éæ°å¢"); |
| | | testDemo.setValue("æµè¯æ°å¢"); |
| | | list.add(testDemo); |
| | | } |
| | | testDemoMapper.insertBatch(list); |
| | | for (int i = 0; i < list.size(); i++) { |
| | | TestDemo testDemo = list.get(i); |
| | | testDemo.setTestKey("æ¹éæ°å¢æä¿®æ¹"); |
| | | testDemo.setValue("æ¹éæ°å¢æä¿®æ¹"); |
| | | if (i % 2 == 0) { |
| | | testDemo.setId(null); |
| | | } |
| | | } |
| | | return toAjax(testDemoMapper.insertOrUpdateBatch(list)); |
| | | } |
| | | |
| | | /** |
| | | * å 餿¹éæ¹æ³ |
| | | */ |
| | | @DeleteMapping() |
| | | // @DS("slave") |
| | | public R<Void> remove() { |
| | | return toAjax(testDemoMapper.delete(new LambdaQueryWrapper<TestDemo>() |
| | | .eq(TestDemo::getOrderNum, -1L))); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import cn.dev33.satoken.annotation.SaCheckPermission; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.utils.MapstructUtils; |
| | | import org.dromara.common.core.utils.ValidatorUtils; |
| | | import org.dromara.common.core.validate.AddGroup; |
| | | import org.dromara.common.core.validate.EditGroup; |
| | | import org.dromara.common.core.validate.QueryGroup; |
| | | import org.dromara.common.web.core.BaseController; |
| | | import org.dromara.common.idempotent.annotation.RepeatSubmit; |
| | | import org.dromara.common.mybatis.core.page.PageQuery; |
| | | import org.dromara.common.mybatis.core.page.TableDataInfo; |
| | | import org.dromara.common.excel.core.ExcelResult; |
| | | import org.dromara.common.excel.utils.ExcelUtil; |
| | | import org.dromara.common.log.annotation.Log; |
| | | import org.dromara.common.log.enums.BusinessType; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import org.dromara.demo.domain.bo.TestDemoBo; |
| | | import org.dromara.demo.domain.bo.TestDemoImportVo; |
| | | import org.dromara.demo.domain.vo.TestDemoVo; |
| | | import org.dromara.demo.service.ITestDemoService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * æµè¯å表Controller |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/demo") |
| | | public class TestDemoController extends BaseController { |
| | | |
| | | private final ITestDemoService testDemoService; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµè¯å表å表 |
| | | */ |
| | | @SaCheckPermission("demo:demo:list") |
| | | @GetMapping("/list") |
| | | public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { |
| | | return testDemoService.queryPageList(bo, pageQuery); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹å页æ¥è¯¢ |
| | | */ |
| | | @SaCheckPermission("demo:demo:list") |
| | | @GetMapping("/page") |
| | | public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { |
| | | return testDemoService.customPageList(bo, pageQuery); |
| | | } |
| | | |
| | | /** |
| | | * 导å
¥æ°æ® |
| | | * |
| | | * @param file 导å
¥æä»¶ |
| | | */ |
| | | @Log(title = "æµè¯å表", businessType = BusinessType.IMPORT) |
| | | @SaCheckPermission("demo:demo:import") |
| | | @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
| | | public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception { |
| | | ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true); |
| | | List<TestDemo> list = MapstructUtils.convert(excelResult.getList(), TestDemo.class); |
| | | testDemoService.saveBatch(list); |
| | | return R.ok(excelResult.getAnalysis()); |
| | | } |
| | | |
| | | /** |
| | | * å¯¼åºæµè¯å表å表 |
| | | */ |
| | | @SaCheckPermission("demo:demo:export") |
| | | @Log(title = "æµè¯å表", businessType = BusinessType.EXPORT) |
| | | @PostMapping("/export") |
| | | public void export(@Validated TestDemoBo bo, HttpServletResponse response) { |
| | | List<TestDemoVo> list = testDemoService.queryList(bo); |
| | | // æµè¯éªè±idå¯¼åº |
| | | // for (TestDemoVo vo : list) { |
| | | // vo.setId(1234567891234567893L); |
| | | // } |
| | | ExcelUtil.exportExcel(list, "æµè¯å表", TestDemoVo.class, response); |
| | | } |
| | | |
| | | /** |
| | | * è·åæµè¯å表详ç»ä¿¡æ¯ |
| | | * |
| | | * @param id æµè¯ID |
| | | */ |
| | | @SaCheckPermission("demo:demo:query") |
| | | @GetMapping("/{id}") |
| | | public R<TestDemoVo> getInfo(@NotNull(message = "主é®ä¸è½ä¸ºç©º") |
| | | @PathVariable("id") Long id) { |
| | | return R.ok(testDemoService.queryById(id)); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢æµè¯å表 |
| | | */ |
| | | @SaCheckPermission("demo:demo:add") |
| | | @Log(title = "æµè¯å表", businessType = BusinessType.INSERT) |
| | | @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}") |
| | | @PostMapping() |
| | | public R<Void> add(@RequestBody TestDemoBo bo) { |
| | | // ä½¿ç¨æ ¡éªå·¥å
·å¯¹æ @Validated(AddGroup.class) 注解 |
| | | // ç¨äºå¨é Controller çå°æ¹æ ¡éªå¯¹è±¡ |
| | | ValidatorUtils.validate(bo, AddGroup.class); |
| | | return toAjax(testDemoService.insertByBo(bo)); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹æµè¯å表 |
| | | */ |
| | | @SaCheckPermission("demo:demo:edit") |
| | | @Log(title = "æµè¯å表", businessType = BusinessType.UPDATE) |
| | | @RepeatSubmit |
| | | @PutMapping() |
| | | public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) { |
| | | return toAjax(testDemoService.updateByBo(bo)); |
| | | } |
| | | |
| | | /** |
| | | * å 餿µè¯å表 |
| | | * |
| | | * @param ids æµè¯ID串 |
| | | */ |
| | | @SaCheckPermission("demo:demo:remove") |
| | | @Log(title = "æµè¯å表", businessType = BusinessType.DELETE) |
| | | @DeleteMapping("/{ids}") |
| | | public R<Void> remove(@NotEmpty(message = "主é®ä¸è½ä¸ºç©º") |
| | | @PathVariable Long[] ids) { |
| | | return toAjax(testDemoService.deleteWithValidByIds(Arrays.asList(ids), true)); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.demo.domain.TestDemoEncrypt; |
| | | import org.dromara.demo.mapper.TestDemoEncryptMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | |
| | | /** |
| | | * æµè¯æ°æ®åºå è§£å¯åè½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Validated |
| | | @RestController |
| | | @RequestMapping("/demo/encrypt") |
| | | public class TestEncryptController { |
| | | |
| | | @Autowired |
| | | private TestDemoEncryptMapper mapper; |
| | | @Value("${mybatis-encryptor.enable}") |
| | | private Boolean encryptEnable; |
| | | |
| | | /** |
| | | * æµè¯æ°æ®åºå è§£å¯ |
| | | * |
| | | * @param key æµè¯key |
| | | * @param value æµè¯value |
| | | */ |
| | | @GetMapping() |
| | | public R<Map<String, TestDemoEncrypt>> test(String key, String value) { |
| | | if (!encryptEnable) { |
| | | throw new RuntimeException("å å¯åè½æªå¼å¯!"); |
| | | } |
| | | Map<String, TestDemoEncrypt> map = new HashMap<>(2); |
| | | TestDemoEncrypt demo = new TestDemoEncrypt(); |
| | | demo.setTestKey(key); |
| | | demo.setValue(value); |
| | | mapper.insert(demo); |
| | | map.put("å å¯", demo); |
| | | TestDemoEncrypt testDemo = mapper.selectById(demo.getId()); |
| | | map.put("è§£å¯", testDemo); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import org.dromara.common.excel.utils.ExcelUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æµè¯Excelåè½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/demo/excel") |
| | | public class TestExcelController { |
| | | |
| | | /** |
| | | * ååè¡¨å¤æ°æ® |
| | | */ |
| | | @GetMapping("/exportTemplateOne") |
| | | public void exportTemplateOne(HttpServletResponse response) { |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("title", "ååè¡¨å¤æ°æ®"); |
| | | map.put("test1", "æ°æ®æµè¯1"); |
| | | map.put("test2", "æ°æ®æµè¯2"); |
| | | map.put("test3", "æ°æ®æµè¯3"); |
| | | map.put("test4", "æ°æ®æµè¯4"); |
| | | map.put("testTest", "666"); |
| | | List<TestObj> list = new ArrayList<>(); |
| | | list.add(new TestObj("åå表æµè¯1", "å表æµè¯1", "å表æµè¯2", "å表æµè¯3", "å表æµè¯4")); |
| | | list.add(new TestObj("åå表æµè¯2", "å表æµè¯5", "å表æµè¯6", "å表æµè¯7", "å表æµè¯8")); |
| | | list.add(new TestObj("åå表æµè¯3", "å表æµè¯9", "å表æµè¯10", "å表æµè¯11", "å表æµè¯12")); |
| | | ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "åå表.xlsx", "excel/åå表.xlsx", response); |
| | | } |
| | | |
| | | /** |
| | | * å¤åè¡¨å¤æ°æ® |
| | | */ |
| | | @GetMapping("/exportTemplateMuliti") |
| | | public void exportTemplateMuliti(HttpServletResponse response) { |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("title1", "æ é¢1"); |
| | | map.put("title2", "æ é¢2"); |
| | | map.put("title3", "æ é¢3"); |
| | | map.put("title4", "æ é¢4"); |
| | | map.put("author", "Lion Li"); |
| | | List<TestObj1> list1 = new ArrayList<>(); |
| | | list1.add(new TestObj1("list1æµè¯1", "list1æµè¯2", "list1æµè¯3")); |
| | | list1.add(new TestObj1("list1æµè¯4", "list1æµè¯5", "list1æµè¯6")); |
| | | list1.add(new TestObj1("list1æµè¯7", "list1æµè¯8", "list1æµè¯9")); |
| | | List<TestObj1> list2 = new ArrayList<>(); |
| | | list2.add(new TestObj1("list2æµè¯1", "list2æµè¯2", "list2æµè¯3")); |
| | | list2.add(new TestObj1("list2æµè¯4", "list2æµè¯5", "list2æµè¯6")); |
| | | List<TestObj1> list3 = new ArrayList<>(); |
| | | list3.add(new TestObj1("list3æµè¯1", "list3æµè¯2", "list3æµè¯3")); |
| | | List<TestObj1> list4 = new ArrayList<>(); |
| | | list4.add(new TestObj1("list4æµè¯1", "list4æµè¯2", "list4æµè¯3")); |
| | | list4.add(new TestObj1("list4æµè¯4", "list4æµè¯5", "list4æµè¯6")); |
| | | list4.add(new TestObj1("list4æµè¯7", "list4æµè¯8", "list4æµè¯9")); |
| | | list4.add(new TestObj1("list4æµè¯10", "list4æµè¯11", "list4æµè¯12")); |
| | | Map<String, Object> multiListMap = new HashMap<>(); |
| | | multiListMap.put("map", map); |
| | | multiListMap.put("data1", list1); |
| | | multiListMap.put("data2", list2); |
| | | multiListMap.put("data3", list3); |
| | | multiListMap.put("data4", list4); |
| | | ExcelUtil.exportTemplateMultiList(multiListMap, "å¤å表.xlsx", "excel/å¤å表.xlsx", response); |
| | | } |
| | | |
| | | @Data |
| | | @AllArgsConstructor |
| | | static class TestObj1 { |
| | | private String test1; |
| | | private String test2; |
| | | private String test3; |
| | | } |
| | | |
| | | @Data |
| | | @AllArgsConstructor |
| | | static class TestObj { |
| | | private String name; |
| | | private String list1; |
| | | private String list2; |
| | | private String list3; |
| | | private String list4; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.utils.MessageUtils; |
| | | import lombok.Data; |
| | | import org.hibernate.validator.constraints.Range; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | |
| | | |
| | | /** |
| | | * æµè¯å½é
å |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | @Validated |
| | | @RestController |
| | | @RequestMapping("/demo/i18n") |
| | | public class TestI18nController { |
| | | |
| | | /** |
| | | * éè¿codeè·åå½é
åå
容 |
| | | * code为 messages.properties ä¸ç key |
| | | * <p> |
| | | * æµè¯ä½¿ç¨ user.register.success |
| | | * |
| | | * @param code å½é
åcode |
| | | */ |
| | | @GetMapping() |
| | | public R<Void> get(String code) { |
| | | return R.ok(MessageUtils.message(code)); |
| | | } |
| | | |
| | | /** |
| | | * Validator æ ¡éªå½é
å |
| | | * ä¸ä¼ å¼ å嫿¥çå¼å¸¸è¿å |
| | | * <p> |
| | | * æµè¯ä½¿ç¨ not.null |
| | | */ |
| | | @GetMapping("/test1") |
| | | public R<Void> test1(@NotBlank(message = "{not.null}") String str) { |
| | | return R.ok(str); |
| | | } |
| | | |
| | | /** |
| | | * Bean æ ¡éªå½é
å |
| | | * ä¸ä¼ å¼ å嫿¥çå¼å¸¸è¿å |
| | | * <p> |
| | | * æµè¯ä½¿ç¨ not.null |
| | | */ |
| | | @GetMapping("/test2") |
| | | public R<TestI18nBo> test2(@Validated TestI18nBo bo) { |
| | | return R.ok(bo); |
| | | } |
| | | |
| | | @Data |
| | | public static class TestI18nBo { |
| | | |
| | | @NotBlank(message = "{not.null}") |
| | | private String name; |
| | | |
| | | @NotNull(message = "{not.null}") |
| | | @Range(min = 0, max = 100, message = "{length.not.valid}") |
| | | private Integer age; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.web.core.BaseController; |
| | | import org.dromara.common.sensitive.annotation.Sensitive; |
| | | import org.dromara.common.sensitive.core.SensitiveStrategy; |
| | | import lombok.Data; |
| | | import org.dromara.common.sensitive.core.SensitiveService; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * æµè¯æ°æ®è±ææ§å¶å¨ |
| | | * <p> |
| | | * é»è®¤ç®¡çåä¸è¿æ»¤ |
| | | * éèªè¡æ ¹æ®ä¸å¡éåå®ç° |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | * @see SensitiveService |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/demo/sensitive") |
| | | public class TestSensitiveController extends BaseController { |
| | | |
| | | /** |
| | | * æµè¯æ°æ®è±æ |
| | | */ |
| | | @GetMapping("/test") |
| | | public R<TestSensitive> test() { |
| | | TestSensitive testSensitive = new TestSensitive(); |
| | | testSensitive.setIdCard("210397198608215431"); |
| | | testSensitive.setPhone("17640125371"); |
| | | testSensitive.setAddress("åäº¬å¸æé³åºææååé¢1203室"); |
| | | testSensitive.setEmail("17640125371@163.com"); |
| | | testSensitive.setBankCard("6226456952351452853"); |
| | | return R.ok(testSensitive); |
| | | } |
| | | |
| | | @Data |
| | | static class TestSensitive { |
| | | |
| | | /** |
| | | * èº«ä»½è¯ |
| | | */ |
| | | @Sensitive(strategy = SensitiveStrategy.ID_CARD) |
| | | private String idCard; |
| | | |
| | | /** |
| | | * çµè¯ |
| | | */ |
| | | @Sensitive(strategy = SensitiveStrategy.PHONE) |
| | | private String phone; |
| | | |
| | | /** |
| | | * å°å |
| | | */ |
| | | @Sensitive(strategy = SensitiveStrategy.ADDRESS) |
| | | private String address; |
| | | |
| | | /** |
| | | * é®ç®± |
| | | */ |
| | | @Sensitive(strategy = SensitiveStrategy.EMAIL) |
| | | private String email; |
| | | |
| | | /** |
| | | * é¶è¡å¡ |
| | | */ |
| | | @Sensitive(strategy = SensitiveStrategy.BANK_CARD) |
| | | private String bankCard; |
| | | |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import cn.dev33.satoken.annotation.SaCheckPermission; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.core.validate.AddGroup; |
| | | import org.dromara.common.core.validate.EditGroup; |
| | | import org.dromara.common.core.validate.QueryGroup; |
| | | import org.dromara.common.web.core.BaseController; |
| | | import org.dromara.common.excel.utils.ExcelUtil; |
| | | import org.dromara.common.idempotent.annotation.RepeatSubmit; |
| | | import org.dromara.common.log.annotation.Log; |
| | | import org.dromara.common.log.enums.BusinessType; |
| | | import org.dromara.demo.domain.bo.TestTreeBo; |
| | | import org.dromara.demo.domain.vo.TestTreeVo; |
| | | import org.dromara.demo.service.ITestTreeService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æµè¯æ 表Controller |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/tree") |
| | | public class TestTreeController extends BaseController { |
| | | |
| | | private final ITestTreeService testTreeService; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµè¯æ 表å表 |
| | | */ |
| | | @SaCheckPermission("demo:tree:list") |
| | | @GetMapping("/list") |
| | | public R<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) { |
| | | List<TestTreeVo> list = testTreeService.queryList(bo); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | /** |
| | | * å¯¼åºæµè¯æ 表å表 |
| | | */ |
| | | @SaCheckPermission("demo:tree:export") |
| | | @Log(title = "æµè¯æ 表", businessType = BusinessType.EXPORT) |
| | | @GetMapping("/export") |
| | | public void export(@Validated TestTreeBo bo, HttpServletResponse response) { |
| | | List<TestTreeVo> list = testTreeService.queryList(bo); |
| | | ExcelUtil.exportExcel(list, "æµè¯æ 表", TestTreeVo.class, response); |
| | | } |
| | | |
| | | /** |
| | | * è·åæµè¯æ 表详ç»ä¿¡æ¯ |
| | | * |
| | | * @param id æµè¯æ ID |
| | | */ |
| | | @SaCheckPermission("demo:tree:query") |
| | | @GetMapping("/{id}") |
| | | public R<TestTreeVo> getInfo(@NotNull(message = "主é®ä¸è½ä¸ºç©º") |
| | | @PathVariable("id") Long id) { |
| | | return R.ok(testTreeService.queryById(id)); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢æµè¯æ 表 |
| | | */ |
| | | @SaCheckPermission("demo:tree:add") |
| | | @Log(title = "æµè¯æ 表", businessType = BusinessType.INSERT) |
| | | @RepeatSubmit |
| | | @PostMapping() |
| | | public R<Void> add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) { |
| | | return toAjax(testTreeService.insertByBo(bo)); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹æµè¯æ 表 |
| | | */ |
| | | @SaCheckPermission("demo:tree:edit") |
| | | @Log(title = "æµè¯æ 表", businessType = BusinessType.UPDATE) |
| | | @RepeatSubmit |
| | | @PutMapping() |
| | | public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) { |
| | | return toAjax(testTreeService.updateByBo(bo)); |
| | | } |
| | | |
| | | /** |
| | | * å 餿µè¯æ 表 |
| | | * |
| | | * @param ids æµè¯æ ID串 |
| | | */ |
| | | @SaCheckPermission("demo:tree:remove") |
| | | @Log(title = "æµè¯æ 表", businessType = BusinessType.DELETE) |
| | | @DeleteMapping("/{ids}") |
| | | public R<Void> remove(@NotEmpty(message = "主é®ä¸è½ä¸ºç©º") |
| | | @PathVariable Long[] ids) { |
| | | return toAjax(testTreeService.deleteWithValidByIds(Arrays.asList(ids), true)); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.websocket.dto.WebSocketMessageDto; |
| | | import org.dromara.common.websocket.utils.WebSocketUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * WebSocket æ¼ç¤ºæ¡ä¾ |
| | | * |
| | | * @author zendwang |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/websocket") |
| | | @Slf4j |
| | | public class WeSocketController { |
| | | |
| | | /** |
| | | * å叿¶æ¯ |
| | | * |
| | | * @param dto åéå
容 |
| | | */ |
| | | @GetMapping("/send") |
| | | public R<Void> send(WebSocketMessageDto dto) throws InterruptedException { |
| | | WebSocketUtils.publishMessage(dto); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller.queue; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.redis.utils.QueueUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * æçéå æ¼ç¤ºæ¡ä¾ |
| | | * <p> |
| | | * è½»é级éå ééçº§æ°æ®é è¯·ä½¿ç¨ MQ |
| | | * <p> |
| | | * é群æµè¯éè¿ åä¸ä¸ªæ°æ®åªä¼è¢«æ¶è´¹ä¸æ¬¡ å好äºå¡è¡¥å¿ |
| | | * é群æµè¯æµç¨ å¨å
¶ä¸ä¸å°åéæ°æ® ä¸¤ç«¯åå«è°ç¨è·åæ¥å£ 䏿¬¡è·å䏿¡ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | */ |
| | | @Slf4j |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/queue/bounded") |
| | | public class BoundedQueueController { |
| | | |
| | | |
| | | /** |
| | | * æ·»å éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param capacity 容é |
| | | */ |
| | | @GetMapping("/add") |
| | | public R<Void> add(String queueName, int capacity) { |
| | | // ç¨å®äºä¸å®è¦éæ¯ å¦åä¼ä¸ç´åå¨ |
| | | boolean b = QueueUtils.destroyQueue(queueName); |
| | | log.info("éé: {} , å é¤: {}", queueName, b); |
| | | // åå§åè®¾ç½®ä¸æ¬¡å³å¯ |
| | | if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) { |
| | | log.info("éé: {} , 设置容é: {}", queueName, capacity); |
| | | } else { |
| | | log.info("éé: {} , 设置容é失败", queueName); |
| | | return R.fail("æä½å¤±è´¥"); |
| | | } |
| | | for (int i = 0; i < 11; i++) { |
| | | String data = "data-" + i; |
| | | boolean flag = QueueUtils.addBoundedQueueObject(queueName, data); |
| | | if (flag == false) { |
| | | log.info("éé: {} , åéæ°æ®: {} 失败, éé已满", queueName, data); |
| | | } else { |
| | | log.info("éé: {} , åéæ°æ®: {}", queueName, data); |
| | | } |
| | | } |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * å é¤éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/remove") |
| | | public R<Void> remove(String queueName) { |
| | | String data = "data-" + 5; |
| | | if (QueueUtils.removeQueueObject(queueName, data)) { |
| | | log.info("éé: {} , å 餿°æ®: {}", queueName, data); |
| | | } else { |
| | | return R.fail("æä½å¤±è´¥"); |
| | | } |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * è·åéåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/get") |
| | | public R<Void> get(String queueName) { |
| | | String data; |
| | | do { |
| | | data = QueueUtils.getQueueObject(queueName); |
| | | log.info("éé: {} , è·åæ°æ®: {}", queueName, data); |
| | | } while (data != null); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller.queue; |
| | | |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.redis.utils.QueueUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * å»¶è¿éå æ¼ç¤ºæ¡ä¾ |
| | | * <p> |
| | | * è½»é级éå ééçº§æ°æ®é è¯·ä½¿ç¨ MQ |
| | | * ä¾å¦: å建订å30åéåè¿æå¤ç |
| | | * <p> |
| | | * é群æµè¯éè¿ åä¸ä¸ªæ°æ®åªä¼è¢«æ¶è´¹ä¸æ¬¡ å好äºå¡è¡¥å¿ |
| | | * é群æµè¯æµç¨ 两å°é群åå«å¼å¯è®¢é
å¨å
¶ä¸ä¸å°åéæ°æ® è§å¯æ¥æ¶æ¶æ¯çè§å¾ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | */ |
| | | @Slf4j |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/queue/delayed") |
| | | public class DelayedQueueController { |
| | | |
| | | /** |
| | | * 订é
éå |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/subscribe") |
| | | public R<Void> subscribe(String queueName) { |
| | | log.info("éé: {} çå¬ä¸......", queueName); |
| | | // 项ç®åå§åè®¾ç½®ä¸æ¬¡å³å¯ |
| | | QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> { |
| | | // è§å¯æ¥æ¶æ¶é´ |
| | | log.info("éé: {}, æ¶å°æ°æ®: {}", queueName, orderNum); |
| | | }); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * æ·»å éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param orderNum 订åå· |
| | | * @param time å»¶è¿æ¶é´(ç§) |
| | | */ |
| | | @GetMapping("/add") |
| | | public R<Void> add(String queueName, String orderNum, Long time) { |
| | | QueueUtils.addDelayedQueueObject(queueName, orderNum, time, TimeUnit.SECONDS); |
| | | // è§å¯åéæ¶é´ |
| | | log.info("éé: {} , åéæ°æ®: {}", queueName, orderNum); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * å é¤éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param orderNum 订åå· |
| | | */ |
| | | @GetMapping("/remove") |
| | | public R<Void> remove(String queueName, String orderNum) { |
| | | if (QueueUtils.removeDelayedQueueObject(queueName, orderNum)) { |
| | | log.info("éé: {} , å 餿°æ®: {}", queueName, orderNum); |
| | | } else { |
| | | return R.fail("æä½å¤±è´¥"); |
| | | } |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * 鿝éå |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/destroy") |
| | | public R<Void> destroy(String queueName) { |
| | | // ç¨å®äºä¸å®è¦éæ¯ å¦åä¼ä¸ç´åå¨ |
| | | QueueUtils.destroyDelayedQueue(queueName); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller.queue; |
| | | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * å®ä½ç±» 注æä¸å
许使ç¨å
é¨ç±» å¦å伿¾ä¸å°ç±» |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | */ |
| | | @Data |
| | | @NoArgsConstructor |
| | | public class PriorityDemo implements Comparable<PriorityDemo> { |
| | | private String name; |
| | | private Integer orderNum; |
| | | |
| | | @Override |
| | | public int compareTo(PriorityDemo other) { |
| | | return Integer.compare(getOrderNum(), other.getOrderNum()); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.controller.queue; |
| | | |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.redis.utils.QueueUtils; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * ä¼å
éå æ¼ç¤ºæ¡ä¾ |
| | | * <p> |
| | | * è½»é级éå ééçº§æ°æ®é è¯·ä½¿ç¨ MQ |
| | | * <p> |
| | | * é群æµè¯éè¿ åä¸ä¸ªæ¶æ¯åªä¼è¢«æ¶è´¹ä¸æ¬¡ å好äºå¡è¡¥å¿ |
| | | * é群æµè¯æµç¨ å¨å
¶ä¸ä¸å°åéæ°æ® ä¸¤ç«¯åå«è°ç¨è·åæ¥å£ 䏿¬¡è·å䏿¡ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.6.0 |
| | | */ |
| | | @Slf4j |
| | | @RequiredArgsConstructor |
| | | @RestController |
| | | @RequestMapping("/demo/queue/priority") |
| | | public class PriorityQueueController { |
| | | |
| | | /** |
| | | * æ·»å éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/add") |
| | | public R<Void> add(String queueName) { |
| | | // ç¨å®äºä¸å®è¦éæ¯ å¦åä¼ä¸ç´åå¨ |
| | | boolean b = QueueUtils.destroyQueue(queueName); |
| | | log.info("éé: {} , å é¤: {}", queueName, b); |
| | | |
| | | for (int i = 0; i < 10; i++) { |
| | | int randomNum = RandomUtil.randomInt(10); |
| | | PriorityDemo data = new PriorityDemo(); |
| | | data.setName("data-" + i); |
| | | data.setOrderNum(randomNum); |
| | | if (QueueUtils.addPriorityQueueObject(queueName, data)) { |
| | | log.info("éé: {} , åéæ°æ®: {}", queueName, data); |
| | | } else { |
| | | log.info("éé: {} , åéæ°æ®: {}, åé失败", queueName, data); |
| | | } |
| | | } |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * å é¤éåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | * @param name 对象å |
| | | * @param orderNum æåºå· |
| | | */ |
| | | @GetMapping("/remove") |
| | | public R<Void> remove(String queueName, String name, Integer orderNum) { |
| | | PriorityDemo data = new PriorityDemo(); |
| | | data.setName(name); |
| | | data.setOrderNum(orderNum); |
| | | if (QueueUtils.removeQueueObject(queueName, data)) { |
| | | log.info("éé: {} , å 餿°æ®: {}", queueName, data); |
| | | } else { |
| | | return R.fail("æä½å¤±è´¥"); |
| | | } |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | /** |
| | | * è·åéåæ°æ® |
| | | * |
| | | * @param queueName éåå |
| | | */ |
| | | @GetMapping("/get") |
| | | public R<Void> get(String queueName) { |
| | | PriorityDemo data; |
| | | do { |
| | | data = QueueUtils.getQueueObject(queueName); |
| | | log.info("éé: {} , è·åæ°æ®: {}", queueName, data); |
| | | } while (data != null); |
| | | return R.ok("æä½æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.*; |
| | | import org.dromara.common.tenant.core.TenantEntity; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æµè¯å表对象 test_demo |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @TableName("test_demo") |
| | | public class TestDemo extends TenantEntity { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | @TableId(value = "id") |
| | | private Long id; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æåºå· |
| | | */ |
| | | @OrderBy(asc = false, sort = 1) |
| | | private Integer orderNum; |
| | | |
| | | /** |
| | | * keyé® |
| | | */ |
| | | private String testKey; |
| | | |
| | | /** |
| | | * å¼ |
| | | */ |
| | | private String value; |
| | | |
| | | /** |
| | | * çæ¬ |
| | | */ |
| | | @Version |
| | | private Long version; |
| | | |
| | | /** |
| | | * å 餿 å¿ |
| | | */ |
| | | @TableLogic |
| | | private Long delFlag; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import org.dromara.common.encrypt.annotation.EncryptField; |
| | | import org.dromara.common.encrypt.enumd.AlgorithmType; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @TableName("test_demo") |
| | | public class TestDemoEncrypt extends TestDemo { |
| | | |
| | | /** |
| | | * keyé® |
| | | */ |
| | | // @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==") |
| | | @EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB") |
| | | private String testKey; |
| | | |
| | | /** |
| | | * å¼ |
| | | */ |
| | | // @EncryptField // ä»ä¹ä¹ä¸åèµ°é»è®¤ymlé
ç½® |
| | | // @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5") |
| | | @EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5") |
| | | private String value; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableLogic; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.baomidou.mybatisplus.annotation.Version; |
| | | import org.dromara.common.tenant.core.TenantEntity; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serial; |
| | | |
| | | /** |
| | | * æµè¯æ 表对象 test_tree |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @TableName("test_tree") |
| | | public class TestTree extends TenantEntity { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | @TableId(value = "id") |
| | | private Long id; |
| | | |
| | | /** |
| | | * ç¶ID |
| | | */ |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æ èç¹å |
| | | */ |
| | | private String treeName; |
| | | |
| | | /** |
| | | * çæ¬ |
| | | */ |
| | | @Version |
| | | private Long version; |
| | | |
| | | /** |
| | | * å 餿 å¿ |
| | | */ |
| | | @TableLogic |
| | | private Long delFlag; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain.bo; |
| | | |
| | | import org.dromara.common.core.validate.AddGroup; |
| | | import org.dromara.common.core.validate.EditGroup; |
| | | import org.dromara.common.mybatis.core.domain.BaseEntity; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import io.github.linpeilie.annotations.AutoMapper; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * æµè¯å表ä¸å¡å¯¹è±¡ test_demo |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @AutoMapper(target = TestDemo.class, reverseConvertGenerate = false) |
| | | public class TestDemoBo extends BaseEntity { |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | @NotNull(message = "主é®ä¸è½ä¸ºç©º", groups = {EditGroup.class}) |
| | | private Long id; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | @NotNull(message = "é¨é¨idä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | @NotNull(message = "ç¨æ·idä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æåºå· |
| | | */ |
| | | @NotNull(message = "æåºå·ä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private Integer orderNum; |
| | | |
| | | /** |
| | | * keyé® |
| | | */ |
| | | @NotBlank(message = "keyé®ä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private String testKey; |
| | | |
| | | /** |
| | | * å¼ |
| | | */ |
| | | @NotBlank(message = "å¼ä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private String value; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain.bo; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import lombok.Data; |
| | | |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * æµè¯å表ä¸å¡å¯¹è±¡ test_demo |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Data |
| | | public class TestDemoImportVo { |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | @NotNull(message = "é¨é¨idä¸è½ä¸ºç©º") |
| | | @ExcelProperty(value = "é¨é¨id") |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | @NotNull(message = "ç¨æ·idä¸è½ä¸ºç©º") |
| | | @ExcelProperty(value = "ç¨æ·id") |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æåºå· |
| | | */ |
| | | @NotNull(message = "æåºå·ä¸è½ä¸ºç©º") |
| | | @ExcelProperty(value = "æåºå·") |
| | | private Long orderNum; |
| | | |
| | | /** |
| | | * keyé® |
| | | */ |
| | | @NotBlank(message = "keyé®ä¸è½ä¸ºç©º") |
| | | @ExcelProperty(value = "keyé®") |
| | | private String testKey; |
| | | |
| | | /** |
| | | * å¼ |
| | | */ |
| | | @NotBlank(message = "å¼ä¸è½ä¸ºç©º") |
| | | @ExcelProperty(value = "å¼") |
| | | private String value; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain.bo; |
| | | |
| | | import org.dromara.common.core.validate.AddGroup; |
| | | import org.dromara.common.core.validate.EditGroup; |
| | | import org.dromara.common.mybatis.core.domain.BaseEntity; |
| | | import org.dromara.demo.domain.TestTree; |
| | | import io.github.linpeilie.annotations.AutoMapper; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * æµè¯æ 表ä¸å¡å¯¹è±¡ test_tree |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @AutoMapper(target = TestTree.class, reverseConvertGenerate = false) |
| | | public class TestTreeBo extends BaseEntity { |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | @NotNull(message = "主é®ä¸è½ä¸ºç©º", groups = {EditGroup.class}) |
| | | private Long id; |
| | | |
| | | /** |
| | | * ç¶ID |
| | | */ |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | @NotNull(message = "é¨é¨idä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | @NotNull(message = "ç¨æ·idä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æ èç¹å |
| | | */ |
| | | @NotBlank(message = "æ èç¹åä¸è½ä¸ºç©º", groups = {AddGroup.class, EditGroup.class}) |
| | | private String treeName; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain.vo; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import org.dromara.common.translation.annotation.Translation; |
| | | import org.dromara.common.translation.constant.TransConstant; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import io.github.linpeilie.annotations.AutoMapper; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | |
| | | |
| | | /** |
| | | * æµè¯å表è§å¾å¯¹è±¡ test_demo |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Data |
| | | @ExcelIgnoreUnannotated |
| | | @AutoMapper(target = TestDemo.class) |
| | | public class TestDemoVo implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | @ExcelProperty(value = "主é®") |
| | | private Long id; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | @ExcelProperty(value = "é¨é¨id") |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | @ExcelProperty(value = "ç¨æ·id") |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æåºå· |
| | | */ |
| | | @ExcelProperty(value = "æåºå·") |
| | | private Integer orderNum; |
| | | |
| | | /** |
| | | * keyé® |
| | | */ |
| | | @ExcelProperty(value = "keyé®") |
| | | private String testKey; |
| | | |
| | | /** |
| | | * å¼ |
| | | */ |
| | | @ExcelProperty(value = "å¼") |
| | | private String value; |
| | | |
| | | /** |
| | | * å建æ¶é´ |
| | | */ |
| | | @ExcelProperty(value = "å建æ¶é´") |
| | | private Date createTime; |
| | | |
| | | /** |
| | | * å建人 |
| | | */ |
| | | @ExcelProperty(value = "å建人") |
| | | private Long createBy; |
| | | |
| | | /** |
| | | * åå»ºäººè´¦å· |
| | | */ |
| | | @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") |
| | | @ExcelProperty(value = "å建人账å·") |
| | | private String createByName; |
| | | |
| | | /** |
| | | * æ´æ°æ¶é´ |
| | | */ |
| | | @ExcelProperty(value = "æ´æ°æ¶é´") |
| | | private Date updateTime; |
| | | |
| | | /** |
| | | * æ´æ°äºº |
| | | */ |
| | | @ExcelProperty(value = "æ´æ°äºº") |
| | | private Long updateBy; |
| | | |
| | | /** |
| | | * æ´æ°äººè´¦å· |
| | | */ |
| | | @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy") |
| | | @ExcelProperty(value = "æ´æ°äººè´¦å·") |
| | | private String updateByName; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.domain.vo; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import org.dromara.demo.domain.TestTree; |
| | | import io.github.linpeilie.annotations.AutoMapper; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serial; |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | |
| | | |
| | | /** |
| | | * æµè¯æ 表è§å¾å¯¹è±¡ test_tree |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @Data |
| | | @ExcelIgnoreUnannotated |
| | | @AutoMapper(target = TestTree.class) |
| | | public class TestTreeVo implements Serializable { |
| | | |
| | | @Serial |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | private Long id; |
| | | |
| | | /** |
| | | * ç¶id |
| | | */ |
| | | @ExcelProperty(value = "ç¶id") |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * é¨é¨id |
| | | */ |
| | | @ExcelProperty(value = "é¨é¨id") |
| | | private Long deptId; |
| | | |
| | | /** |
| | | * ç¨æ·id |
| | | */ |
| | | @ExcelProperty(value = "ç¨æ·id") |
| | | private Long userId; |
| | | |
| | | /** |
| | | * æ èç¹å |
| | | */ |
| | | @ExcelProperty(value = "æ èç¹å") |
| | | private String treeName; |
| | | |
| | | /** |
| | | * å建æ¶é´ |
| | | */ |
| | | @ExcelProperty(value = "å建æ¶é´") |
| | | private Date createTime; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.mapper; |
| | | |
| | | import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
| | | import org.dromara.demo.domain.TestDemoEncrypt; |
| | | |
| | | /** |
| | | * æµè¯å å¯åè½ |
| | | * |
| | | * @author Lion Li |
| | | */ |
| | | public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncrypt, TestDemoEncrypt> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Constants; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import org.dromara.common.mybatis.annotation.DataColumn; |
| | | import org.dromara.common.mybatis.annotation.DataPermission; |
| | | import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import org.dromara.demo.domain.vo.TestDemoVo; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æµè¯å表Mapperæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> { |
| | | |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper); |
| | | |
| | | @Override |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | <P extends IPage<TestDemo>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper); |
| | | |
| | | @Override |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper); |
| | | |
| | | @Override |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | int updateById(@Param(Constants.ENTITY) TestDemo entity); |
| | | |
| | | @Override |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | int deleteBatchIds(@Param(Constants.COLL) Collection<?> idList); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.mapper; |
| | | |
| | | import org.dromara.common.mybatis.annotation.DataColumn; |
| | | import org.dromara.common.mybatis.annotation.DataPermission; |
| | | import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
| | | import org.dromara.demo.domain.TestTree; |
| | | import org.dromara.demo.domain.vo.TestTreeVo; |
| | | |
| | | /** |
| | | * æµè¯æ 表Mapperæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @DataPermission({ |
| | | @DataColumn(key = "deptName", value = "dept_id"), |
| | | @DataColumn(key = "userName", value = "user_id") |
| | | }) |
| | | public interface TestTreeMapper extends BaseMapperPlus<TestTree, TestTreeVo> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.mapper; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.service; |
| | | |
| | | import org.dromara.common.mybatis.core.page.PageQuery; |
| | | import org.dromara.common.mybatis.core.page.TableDataInfo; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import org.dromara.demo.domain.bo.TestDemoBo; |
| | | import org.dromara.demo.domain.vo.TestDemoVo; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æµè¯å表Serviceæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | public interface ITestDemoService { |
| | | |
| | | /** |
| | | * æ¥è¯¢å个 |
| | | * |
| | | * @return |
| | | */ |
| | | TestDemoVo queryById(Long id); |
| | | |
| | | /** |
| | | * æ¥è¯¢å表 |
| | | */ |
| | | TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery); |
| | | |
| | | /** |
| | | * èªå®ä¹å页æ¥è¯¢ |
| | | */ |
| | | TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery); |
| | | |
| | | /** |
| | | * æ¥è¯¢å表 |
| | | */ |
| | | List<TestDemoVo> queryList(TestDemoBo bo); |
| | | |
| | | /** |
| | | * æ ¹æ®æ°å¢ä¸å¡å¯¹è±¡æå
¥æµè¯å表 |
| | | * |
| | | * @param bo æµè¯å表æ°å¢ä¸å¡å¯¹è±¡ |
| | | * @return |
| | | */ |
| | | Boolean insertByBo(TestDemoBo bo); |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼è¾ä¸å¡å¯¹è±¡ä¿®æ¹æµè¯å表 |
| | | * |
| | | * @param bo æµè¯å表ç¼è¾ä¸å¡å¯¹è±¡ |
| | | * @return |
| | | */ |
| | | Boolean updateByBo(TestDemoBo bo); |
| | | |
| | | /** |
| | | * æ ¡éªå¹¶å 餿°æ® |
| | | * |
| | | * @param ids 主é®éå |
| | | * @param isValid æ¯å¦æ ¡éª,true-å é¤åæ ¡éª,false-䏿 ¡éª |
| | | * @return |
| | | */ |
| | | Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
| | | |
| | | /** |
| | | * æ¹éä¿å |
| | | */ |
| | | Boolean saveBatch(List<TestDemo> list); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.service; |
| | | |
| | | import org.dromara.demo.domain.bo.TestTreeBo; |
| | | import org.dromara.demo.domain.vo.TestTreeVo; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æµè¯æ 表Serviceæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | public interface ITestTreeService { |
| | | /** |
| | | * æ¥è¯¢å个 |
| | | * |
| | | * @return |
| | | */ |
| | | TestTreeVo queryById(Long id); |
| | | |
| | | /** |
| | | * æ¥è¯¢å表 |
| | | */ |
| | | List<TestTreeVo> queryList(TestTreeBo bo); |
| | | |
| | | /** |
| | | * æ ¹æ®æ°å¢ä¸å¡å¯¹è±¡æå
¥æµè¯æ 表 |
| | | * |
| | | * @param bo æµè¯æ 表æ°å¢ä¸å¡å¯¹è±¡ |
| | | * @return |
| | | */ |
| | | Boolean insertByBo(TestTreeBo bo); |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼è¾ä¸å¡å¯¹è±¡ä¿®æ¹æµè¯æ 表 |
| | | * |
| | | * @param bo æµè¯æ 表ç¼è¾ä¸å¡å¯¹è±¡ |
| | | * @return |
| | | */ |
| | | Boolean updateByBo(TestTreeBo bo); |
| | | |
| | | /** |
| | | * æ ¡éªå¹¶å 餿°æ® |
| | | * |
| | | * @param ids 主é®éå |
| | | * @param isValid æ¯å¦æ ¡éª,true-å é¤åæ ¡éª,false-䏿 ¡éª |
| | | * @return |
| | | */ |
| | | Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import org.dromara.common.core.utils.MapstructUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.mybatis.core.page.PageQuery; |
| | | import org.dromara.common.mybatis.core.page.TableDataInfo; |
| | | import org.dromara.demo.domain.TestDemo; |
| | | import org.dromara.demo.domain.bo.TestDemoBo; |
| | | import org.dromara.demo.domain.vo.TestDemoVo; |
| | | import org.dromara.demo.mapper.TestDemoMapper; |
| | | import org.dromara.demo.service.ITestDemoService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æµè¯å表Serviceä¸å¡å±å¤ç |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | @RequiredArgsConstructor |
| | | @Service |
| | | public class TestDemoServiceImpl implements ITestDemoService { |
| | | |
| | | private final TestDemoMapper baseMapper; |
| | | |
| | | @Override |
| | | public TestDemoVo queryById(Long id) { |
| | | return baseMapper.selectVoById(id); |
| | | } |
| | | |
| | | @Override |
| | | public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) { |
| | | LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo); |
| | | Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
| | | return TableDataInfo.build(result); |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹å页æ¥è¯¢ |
| | | */ |
| | | @Override |
| | | public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) { |
| | | LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo); |
| | | Page<TestDemoVo> result = baseMapper.customPageList(pageQuery.build(), lqw); |
| | | return TableDataInfo.build(result); |
| | | } |
| | | |
| | | @Override |
| | | public List<TestDemoVo> queryList(TestDemoBo bo) { |
| | | return baseMapper.selectVoList(buildQueryWrapper(bo)); |
| | | } |
| | | |
| | | private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) { |
| | | Map<String, Object> params = bo.getParams(); |
| | | LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery(); |
| | | lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); |
| | | lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); |
| | | lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, |
| | | TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); |
| | | return lqw; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean insertByBo(TestDemoBo bo) { |
| | | TestDemo add = MapstructUtils.convert(bo, TestDemo.class); |
| | | validEntityBeforeSave(add); |
| | | boolean flag = baseMapper.insert(add) > 0; |
| | | if (flag) { |
| | | bo.setId(add.getId()); |
| | | } |
| | | return flag; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateByBo(TestDemoBo bo) { |
| | | TestDemo update = MapstructUtils.convert(bo, TestDemo.class); |
| | | validEntityBeforeSave(update); |
| | | return baseMapper.updateById(update) > 0; |
| | | } |
| | | |
| | | /** |
| | | * ä¿ååçæ°æ®æ ¡éª |
| | | * |
| | | * @param entity å®ä½ç±»æ°æ® |
| | | */ |
| | | private void validEntityBeforeSave(TestDemo entity) { |
| | | //TODO åä¸äºæ°æ®æ ¡éª,å¦å¯ä¸çº¦æ |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
| | | if (isValid) { |
| | | //TODO åä¸äºä¸å¡ä¸çæ ¡éª,夿æ¯å¦éè¦æ ¡éª |
| | | } |
| | | return baseMapper.deleteBatchIds(ids) > 0; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean saveBatch(List<TestDemo> list) { |
| | | return baseMapper.insertBatch(list); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import org.dromara.common.core.utils.MapstructUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.demo.domain.TestTree; |
| | | import org.dromara.demo.domain.bo.TestTreeBo; |
| | | import org.dromara.demo.domain.vo.TestTreeVo; |
| | | import org.dromara.demo.mapper.TestTreeMapper; |
| | | import org.dromara.demo.service.ITestTreeService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æµè¯æ 表Serviceä¸å¡å±å¤ç |
| | | * |
| | | * @author Lion Li |
| | | * @date 2021-07-26 |
| | | */ |
| | | // @DS("slave") // 忢ä»åºæ¥è¯¢ |
| | | @RequiredArgsConstructor |
| | | @Service |
| | | public class TestTreeServiceImpl implements ITestTreeService { |
| | | |
| | | private final TestTreeMapper baseMapper; |
| | | |
| | | @Override |
| | | public TestTreeVo queryById(Long id) { |
| | | return baseMapper.selectVoById(id); |
| | | } |
| | | |
| | | // @DS("slave") // 忢ä»åºæ¥è¯¢ |
| | | @Override |
| | | public List<TestTreeVo> queryList(TestTreeBo bo) { |
| | | LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo); |
| | | return baseMapper.selectVoList(lqw); |
| | | } |
| | | |
| | | private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) { |
| | | Map<String, Object> params = bo.getParams(); |
| | | LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery(); |
| | | lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); |
| | | lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, |
| | | TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); |
| | | return lqw; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean insertByBo(TestTreeBo bo) { |
| | | TestTree add = MapstructUtils.convert(bo, TestTree.class); |
| | | validEntityBeforeSave(add); |
| | | boolean flag = baseMapper.insert(add) > 0; |
| | | if (flag) { |
| | | bo.setId(add.getId()); |
| | | } |
| | | return flag; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateByBo(TestTreeBo bo) { |
| | | TestTree update = MapstructUtils.convert(bo, TestTree.class); |
| | | validEntityBeforeSave(update); |
| | | return baseMapper.updateById(update) > 0; |
| | | } |
| | | |
| | | /** |
| | | * ä¿ååçæ°æ®æ ¡éª |
| | | * |
| | | * @param entity å®ä½ç±»æ°æ® |
| | | */ |
| | | private void validEntityBeforeSave(TestTree entity) { |
| | | //TODO åä¸äºæ°æ®æ ¡éª,å¦å¯ä¸çº¦æ |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
| | | if (isValid) { |
| | | //TODO åä¸äºä¸å¡ä¸çæ ¡éª,夿æ¯å¦éè¦æ ¡éª |
| | | } |
| | | return baseMapper.deleteBatchIds(ids) > 0; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.demo.service.impl; |
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml
ruoyi-modules/ruoyi-generator/pom.xml
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/constant/GenConstants.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java (已删除)
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml
ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
ruoyi-modules/ruoyi-job/pom.xml
ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SampleService.java (已删除)
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/SampleService.java
ruoyi-modules/ruoyi-system/pom.xml
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysOperlogController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysConfigController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDeptController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictDataController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictTypeController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysMenuController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysNoticeController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysOssConfigController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysOssController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysPostController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysRoleController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysTenantController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysTenantPackageController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysUserController.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOss.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTenant.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTenantPackage.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysConfigBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDeptBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictDataBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictTypeBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysLogininforBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysMenuBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysNoticeBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOperLogBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysPostBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysRoleBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysTenantBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysTenantPackageBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AvatarVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CacheListInfoVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeptTreeSelectVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuTreeSelectVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ProfileVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysConfigVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDeptVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictDataVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictTypeVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysLogininforVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysMenuVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysNoticeVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssConfigVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssUploadVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysPostVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysRoleVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysTenantPackageVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysTenantVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserInfoVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserInfoVo.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssConfigMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTenantMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTenantPackageMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDataScopeService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTenantPackageService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTenantService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDataScopeServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysSensitiveServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantPackageServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java (已删除)
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml |