commit 664269099ae28dea455e595bdadd44b4fdcc8bd6 Author: haoqiong liu Date: Tue Jul 28 17:31:47 2020 +0800 创建基础包,完成Shiro封装 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19b3f66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +mvnw +mvnw.cmd + + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..141a917 --- /dev/null +++ b/README.en.md @@ -0,0 +1,36 @@ +# common + +#### Description +{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} + +#### Software Architecture +Software architecture description + +#### Installation + +1. xxxx +2. xxxx +3. xxxx + +#### Instructions + +1. xxxx +2. xxxx +3. xxxx + +#### Contribution + +1. Fork the repository +2. Create Feat_xxx branch +3. Commit your code +4. Create Pull Request + + +#### Gitee Feature + +1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md +2. Gitee blog [blog.gitee.com](https://blog.gitee.com) +3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) +4. The most valuable open source project [GVP](https://gitee.com/gvp) +5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) +6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec0fe2f --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# common + +#### 介绍 +{**以下是码云平台说明,您可以替换此简介** +码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 +无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} + +#### 软件架构 +软件架构说明 + + +#### 安装教程 + +1. xxxx +2. xxxx +3. xxxx + +#### 使用说明 + +1. xxxx +2. xxxx +3. xxxx + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 +4. 新建 Pull Request + + +#### 码云特技 + +1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md +2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) +3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 +4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 +5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) +6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/lib/Dm7JdbcDriver18.jar b/lib/Dm7JdbcDriver18.jar new file mode 100644 index 0000000..deb4562 Binary files /dev/null and b/lib/Dm7JdbcDriver18.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..78b9567 --- /dev/null +++ b/pom.xml @@ -0,0 +1,171 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + com.common.base + base + 0.0.1-SNAPSHOT + jar + common-base + 基础包 + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.2 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.aspectj + aspectjrt + 1.8.0 + + + org.aspectj + aspectjweaver + + + com.alibaba + fastjson + 1.2.59 + + + com.github.xiaoymin + knife4j-spring-boot-starter + 2.0.2 + + + + javax.validation + validation-api + 2.0.1.Final + + + org.apache.shiro + shiro-spring + 1.3.2 + + + org.apache.commons + commons-lang3 + 3.10 + + + commons-io + commons-io + 2.6 + + + javax.mail + mail + 1.4.7 + + + tk.mybatis + mapper-spring-boot-starter + 2.1.5 + + + com.alibaba + druid-spring-boot-starter + 1.1.1 + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.2.13 + + + org.apache.commons + commons-pool2 + 2.6.2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + common-base + + + org.apache.maven.plugins + maven-war-plugin + + + + + ${project.basedir}/lib/ + WEB-INF/lib/ + + **/*.jar + + + + + + + org.mybatis.generator + mybatis-generator-maven-plugin + 1.3.7 + + ../common/src/main/resources/generatorConfig.xml + true + true + + + + + + diff --git a/src/main/java/com/common/base/annotation/LogAnno.java b/src/main/java/com/common/base/annotation/LogAnno.java new file mode 100644 index 0000000..bb1248d --- /dev/null +++ b/src/main/java/com/common/base/annotation/LogAnno.java @@ -0,0 +1,26 @@ +package com.common.base.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 日志注解 + * + * @author lhc + */ +// 方法注解 +@Target(ElementType.METHOD) +// 运行时可见 +@Retention(RetentionPolicy.RUNTIME) +public @interface LogAnno { + // 记录日志的操作类型 + String operateType(); + // 记录日志主键 + String primaryKey() default "id"; + // 记录日志表 + String tableName() default "-"; + + boolean isBefore() default false; +} diff --git a/src/main/java/com/common/base/common/ControllerExceptionHandler.java b/src/main/java/com/common/base/common/ControllerExceptionHandler.java new file mode 100644 index 0000000..194f3e3 --- /dev/null +++ b/src/main/java/com/common/base/common/ControllerExceptionHandler.java @@ -0,0 +1,34 @@ +package com.common.base.common; + +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authz.AuthorizationException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +/*** + * @description 异常信息拦截类,如果程序运行过程中抛出异常,会将异常拦截下来,并返回前端一个包含异常信息的Json数据 + */ + +@ControllerAdvice +public class ControllerExceptionHandler { + + @ExceptionHandler(Exception.class) + @ResponseBody + public ResultVO handleServiceException( + Exception e) { + if (e instanceof AuthorizationException) { + return ResultVO.getNoAuthorization(); + } else if (e instanceof AuthenticationException) { + return ResultVO.getFailed("用户名或密码错误"); + } else if (e instanceof RuntimeException) { + System.out.println("handleServiceException"); + e.printStackTrace(); + //封装错误信息 + return ResultVO.getException(e); + } else { + return ResultVO.getException(e); + } + } + //....... +} diff --git a/src/main/java/com/common/base/common/Mapper.java b/src/main/java/com/common/base/common/Mapper.java new file mode 100644 index 0000000..5c77d86 --- /dev/null +++ b/src/main/java/com/common/base/common/Mapper.java @@ -0,0 +1,15 @@ +package com.common.base.common; + +import tk.mybatis.mapper.common.*; + +/*** + * @description 调用tkmapper进行接口封装 + * @param + */ +public interface Mapper extends + BaseMapper, + ExampleMapper, + RowBoundsMapper, + Marker, ConditionMapper, tk.mybatis.mapper.common.Mapper { + +} diff --git a/src/main/java/com/common/base/common/RestControllerExceptionHandler.java b/src/main/java/com/common/base/common/RestControllerExceptionHandler.java new file mode 100644 index 0000000..ece2169 --- /dev/null +++ b/src/main/java/com/common/base/common/RestControllerExceptionHandler.java @@ -0,0 +1,22 @@ +package com.common.base.common; + +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/*** + * @description 异常信息拦截类,如果程序运行过程中抛出异常,会将异常拦截下来,并返回前端一个包含异常信息的Json数据 + */ + +@RestControllerAdvice +public class RestControllerExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResultVO handleServiceException( + RuntimeException e){ + System.out.println("handleServiceException"); + e.printStackTrace(); + //封装错误信息 + return ResultVO.getException(e); + } + //....... +} diff --git a/src/main/java/com/common/base/common/ResultVO.java b/src/main/java/com/common/base/common/ResultVO.java new file mode 100644 index 0000000..0523e99 --- /dev/null +++ b/src/main/java/com/common/base/common/ResultVO.java @@ -0,0 +1,155 @@ +package com.common.base.common; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author lhc + * @description 返回结果VO对象 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResultVO { + + private static final Integer SUCCESS = 0; + private static final Integer FAILED = 1; + private static final Integer ERROR = 2; + private static final Integer UNLOG = 3; + private static final Integer NOAUTH = 4; + //("状态码 0成功 1失败 2服务器出错 3未登录 4没有权限") + private Integer code=SUCCESS; + + //("返回信息") + @ApiModelProperty(example="ActionOK") + private String msg; + + //("返回数据") + private T data; + + private ResultVO() { + this.code = SUCCESS; + this.msg = "Action OK"; + } + private ResultVO(T data) { + this.code = SUCCESS; + this.msg = "Action OK"; + this.data = data; + } + + private ResultVO(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + private ResultVO(Integer code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + private ResultVO(Throwable exp){ + this.code=ERROR; + this.msg=exp.getMessage(); + } + /** + * 请求成功 状态码 1 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess(T data) { + return new ResultVO(data); + } + /** + * 请求成功 状态码 1 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess() { + return new ResultVO(); + } + /** + * 请求成功 状态码 1 + * + * @param msg 返回信息 + * @param data 返回对象 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess(String msg, T data) { + return new ResultVO(SUCCESS, msg, data); + } + + /** + * 请求失败 状态码 0 + * + * @param msg 返回信息 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getFailed(String msg) { + return new ResultVO(FAILED, msg); + } + + /** + * 请求失败 状态 0 + * + * @param msg 返回信息 + * @param data 返回数据 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getFailed(String msg, T data) { + return new ResultVO(FAILED, msg, data); + } + + + /** + * 用户未登录 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getNoLogin() { + return new ResultVO(UNLOG, "用户未登录,请重新登录"); + } + + + /** + * 用户没有操作权限 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getNoAuthorization() { + return new ResultVO(NOAUTH, "用户没有操作权限,请重新登录"); + } + + public static ResultVO getException(Throwable exp) { + return new ResultVO(exp); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/src/main/java/com/common/base/common/ServiceException.java b/src/main/java/com/common/base/common/ServiceException.java new file mode 100644 index 0000000..aedc976 --- /dev/null +++ b/src/main/java/com/common/base/common/ServiceException.java @@ -0,0 +1,27 @@ +package com.common.base.common; + +/*** + * @description 自定义异常类 + */ +public class ServiceException extends RuntimeException { + + public ServiceException() { + + } + + public ServiceException(String message) { + super(message); + } + + public ServiceException(String message, Throwable cause) { + super(message, cause); + } + + public ServiceException(Throwable cause) { + super(cause); + } + + public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/common/base/common/WebPatternlLog.java b/src/main/java/com/common/base/common/WebPatternlLog.java new file mode 100644 index 0000000..1f38da6 --- /dev/null +++ b/src/main/java/com/common/base/common/WebPatternlLog.java @@ -0,0 +1,63 @@ +package com.common.base.common; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; + +/*** + * 通过Aop拦截访问接口(Controller)的URL,参数,IP等信息 + */ +@Aspect +@Component +public class WebPatternlLog { + + private final static Logger logger = LoggerFactory.getLogger(WebPatternlLog.class); + + //这个切点的表达式需要根据自己的项目来写 + @Pointcut("execution(public * com.common.base.controller..*(..))") + public void log() { + + } + + @Before("log()") + public void doBefore(JoinPoint joinPoint) { + //logger.info("aop doBefore.."); + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletRequest request = attributes.getRequest(); + + //url + logger.info("url={}", request.getRequestURI()); + + //method + logger.info("method={}", request.getMethod()); + + //ip + logger.info("ip={}", request.getRemoteAddr()); + + //类方法 + logger.info("classMethod={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); + + //参数 + Enumeration paramter = request.getParameterNames(); + while (paramter.hasMoreElements()) { + String str = (String) paramter.nextElement(); + logger.info(str + "={}", request.getParameter(str)); + } + + } + + @After("log()") + public void doAfter() { + //logger.info("aop doAfter"); + } +} diff --git a/src/main/java/com/common/base/config/GetHttpSession.java b/src/main/java/com/common/base/config/GetHttpSession.java new file mode 100644 index 0000000..078ccb7 --- /dev/null +++ b/src/main/java/com/common/base/config/GetHttpSession.java @@ -0,0 +1,22 @@ +package com.common.base.config; + +import javax.servlet.http.HttpSession; +import javax.websocket.HandshakeResponse; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpointConfig; +import javax.websocket.server.ServerEndpointConfig.Configurator; +/* + * 获取HttpSession + * + */ + +public class GetHttpSession extends Configurator { + + @Override + public void modifyHandshake(ServerEndpointConfig sec, + HandshakeRequest request, HandshakeResponse response) { + HttpSession httpSession=(HttpSession) request.getHttpSession(); + sec.getUserProperties().put(HttpSession.class.getName(),httpSession); + } + +} diff --git a/src/main/java/com/common/base/config/RedisConfig.java b/src/main/java/com/common/base/config/RedisConfig.java new file mode 100644 index 0000000..59b9b2b --- /dev/null +++ b/src/main/java/com/common/base/config/RedisConfig.java @@ -0,0 +1,36 @@ +package com.common.base.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * @description redis配置类 + * @author lhc + * @date 2020-06-15 + */ +@Configuration +public class RedisConfig { + + /** + * springboot2.x 使用LettuceConnectionFactory 代替 RedisConnectionFactory + * application.yml配置基本信息后,springboot2.x RedisAutoConfiguration能够自动装配 + * LettuceConnectionFactory 和 RedisConnectionFactory 及其 RedisTemplate + * @param redisConnectionFactory + * @return + */ + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory redisConnectionFactory){ + RedisTemplate redisTemplate = new RedisTemplate(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setConnectionFactory(redisConnectionFactory); + return redisTemplate; + } + +} diff --git a/src/main/java/com/common/base/config/SimpleCORSFilter.java b/src/main/java/com/common/base/config/SimpleCORSFilter.java new file mode 100644 index 0000000..c734a71 --- /dev/null +++ b/src/main/java/com/common/base/config/SimpleCORSFilter.java @@ -0,0 +1,57 @@ +package com.common.base.config; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 跨域支持 + + */ +@WebFilter +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleCORSFilter implements Filter { + + @Override + public void destroy() { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + /*String[] whiteList = {"http://fwh.castscs.org.cn", "http://localhost"}; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + boolean isValid = false; + for( String ip : whiteList ) { + if( myOrigin != null && myOrigin.equals(ip) ){ + isValid = true; + break; + } + }*/ + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + httpServletResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); + httpServletResponse.setHeader("Access-Control-Max-Age", "3600"); + httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, X-Access-Token"); + // 是否支持cookie跨域 + httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true"); + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + + } + +} diff --git a/src/main/java/com/common/base/config/WebMvcConfig.java b/src/main/java/com/common/base/config/WebMvcConfig.java new file mode 100644 index 0000000..42fd14b --- /dev/null +++ b/src/main/java/com/common/base/config/WebMvcConfig.java @@ -0,0 +1,9 @@ +package com.common.base.config; + +import org.springframework.stereotype.Component; +import org.springframework.web.filter.FormContentFilter; + +@Component +public class WebMvcConfig extends FormContentFilter { + +} diff --git a/src/main/java/com/common/base/config/webSessionListener.java b/src/main/java/com/common/base/config/webSessionListener.java new file mode 100644 index 0000000..e3c7670 --- /dev/null +++ b/src/main/java/com/common/base/config/webSessionListener.java @@ -0,0 +1,23 @@ +package com.common.base.config; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; + +@WebListener +public class webSessionListener implements ServletRequestListener { + + @Override + public void requestInitialized(ServletRequestEvent sre) { + //将所有request请求都携带上httpSession + ((HttpServletRequest) sre.getServletRequest()).getSession(); + + } + public webSessionListener() { + } + + @Override + public void requestDestroyed(ServletRequestEvent arg0) { + } +} diff --git a/src/main/java/com/common/base/dao/FtTokenDao.java b/src/main/java/com/common/base/dao/FtTokenDao.java new file mode 100644 index 0000000..1cd3c95 --- /dev/null +++ b/src/main/java/com/common/base/dao/FtTokenDao.java @@ -0,0 +1,16 @@ +package com.common.base.dao; + + +import com.common.base.common.Mapper; +import com.common.base.entity.FtToken; + +/** + * (FtToken)表数据库访问层 + * + * @author lhc + * @since 2020-02-11 20:26:15 + */ +public interface FtTokenDao extends Mapper { + + +} diff --git a/src/main/java/com/common/base/entity/FtToken.java b/src/main/java/com/common/base/entity/FtToken.java new file mode 100644 index 0000000..60aee0c --- /dev/null +++ b/src/main/java/com/common/base/entity/FtToken.java @@ -0,0 +1,41 @@ +package com.common.base.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import java.io.Serializable; +import java.util.Date; + +/** + * (FtToken)实体类 + * + * @author lhc + * @since 2020-02-11 20:26:15 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +@Data +public class FtToken implements Serializable { + private static final long serialVersionUID = 202774093136745829L; + + @Id + @GeneratedValue( + strategy = GenerationType.IDENTITY, + generator = "select TOKEN_ID.nextval from dual") + private String tokenId; + + private String token; + + private String userId; + + private Date updateTime; + + private Date expireTime; + +} diff --git a/src/main/java/com/common/base/shiro/AuthFilter.java b/src/main/java/com/common/base/shiro/AuthFilter.java new file mode 100644 index 0000000..f4808d4 --- /dev/null +++ b/src/main/java/com/common/base/shiro/AuthFilter.java @@ -0,0 +1,138 @@ +package com.common.base.shiro; + +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.web.filter.authc.AuthenticatingFilter; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * auth过滤器 + * + * @Author lhc + */ +public class AuthFilter extends AuthenticatingFilter { + + /** + * 生成自定义token + * + * @param request + * @param response + * @return + * @throws Exception + */ + @Override + protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { + //获取请求token + String token = getRequestToken((HttpServletRequest) request); + if (StringUtils.isBlank(token)) { + HttpServletResponse httpResponse = (HttpServletResponse) response; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + httpResponse.setContentType("application/json;charset=utf-8"); + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpResponse.setCharacterEncoding("UTF-8"); + Map result = new HashMap<>(); + result.put("code", 3); + result.put("msg", "未登陆"); + String json = JSON.toJSONString(result); + httpResponse.getWriter().print(json); + return null; + } + return new AuthToken(token); + } + + /** + * 步骤1.所有请求全部拒绝访问 + * + * @param request + * @param response + * @param mappedValue + * @return + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + return ((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name()); + } + + /** + * 步骤2,拒绝访问的请求,会调用onAccessDenied方法,onAccessDenied方法先获取 token,再调用executeLogin方法 + * + * @param request + * @param response + * @return + * @throws Exception + */ + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + //获取请求token,如果token不存在,直接返回 + String token = getRequestToken((HttpServletRequest) request); + if (StringUtils.isBlank(token)) { + HttpServletResponse httpResponse = (HttpServletResponse) response; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + httpResponse.setContentType("application/json;charset=utf-8"); + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpResponse.setCharacterEncoding("UTF-8"); + Map result = new HashMap<>(); + result.put("code", 3); + result.put("msg", "未登陆"); + String json = JSON.toJSONString(result); + httpResponse.getWriter().print(json); + return false; + } + return executeLogin(request, response); + } + + /** + * 登陆失败时候调用 + */ + @Override + protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { + //处理登录失败的异常 + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setContentType("application/json;charset=utf-8"); + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + httpResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpResponse.setCharacterEncoding("UTF-8"); + try { + //处理登录失败的异常 + Throwable throwable = e.getCause() == null ? e : e.getCause(); + Map result = new HashMap<>(); + result.put("code", 3); + result.put("msg", "未登陆"); + String json = JSON.toJSONString(result); + httpResponse.getWriter().print(json); + } catch (IOException e1) { + } + return false; + } + + /** + * 获取请求的token + */ + private String getRequestToken(HttpServletRequest httpRequest) { + //从header中获取token + String token = httpRequest.getHeader("X-Access-Token"); + //如果header中不存在token,则从参数中获取token + if (StringUtils.isBlank(token)) { + if (StringUtils.isBlank(token)) { + token = httpRequest.getParameter("token"); + } + } + return token; + } +} diff --git a/src/main/java/com/common/base/shiro/AuthToken.java b/src/main/java/com/common/base/shiro/AuthToken.java new file mode 100644 index 0000000..945df30 --- /dev/null +++ b/src/main/java/com/common/base/shiro/AuthToken.java @@ -0,0 +1,26 @@ +package com.common.base.shiro; + +import org.apache.shiro.authc.AuthenticationToken; + +/** + * 自定义AuthenticationToken类 + * @Author lhc + */ +public class AuthToken implements AuthenticationToken { + + private String token; + + public AuthToken(String token) { + this.token = token; + } + + @Override + public Object getPrincipal() { + return token; + } + + @Override + public Object getCredentials() { + return token; + } +} diff --git a/src/main/java/com/common/base/shiro/CustomRealm.java b/src/main/java/com/common/base/shiro/CustomRealm.java new file mode 100644 index 0000000..a6c2cf2 --- /dev/null +++ b/src/main/java/com/common/base/shiro/CustomRealm.java @@ -0,0 +1,81 @@ +package com.common.base.shiro; + + +import com.common.base.entity.FtToken; +import com.common.base.shiro.service.ShiroService; +import com.common.base.shiro.service.SystemRealm; +import com.common.base.utils.RedisUtil; +import org.apache.shiro.authc.*; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.Map; + +public class CustomRealm extends AuthorizingRealm { + + @Resource + private ShiroService shiroService; + + @Resource + private RedisUtil redisUtil; + + @Resource + private SystemRealm systemRealm; + + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { + //1. 从 PrincipalCollection 中来获取登录用户的信息 + Object user = principalCollection.getPrimaryPrincipal(); + return systemRealm.setAuthoriztion(user); + } + + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { + String accessToken = (String) token.getPrincipal(); + String userId; + if (RedisUtil.isUseful) { + Map hashMap = redisUtil.hmget(accessToken); + userId = (String) hashMap.get("userId"); + if (userId == null) { + throw new IncorrectCredentialsException("token失效,请重新登录"); + } + String tokenStr = (String) redisUtil.hget("session", String.valueOf(userId)); + if (tokenStr==null||!tokenStr.equals(accessToken)) { + redisUtil.del(accessToken); + throw new IncorrectCredentialsException("token失效,请重新登录"); + } + Date expireTime = (Date) hashMap.get("expireTime"); + System.out.println(expireTime); + if (expireTime.getTime() < System.currentTimeMillis()) { + redisUtil.del(accessToken); + throw new IncorrectCredentialsException("token失效,请重新登录"); + } + } else { + //1. 根据accessToken,查询用户信息 + FtToken tokenEntity = shiroService.findByToken(accessToken); + userId = tokenEntity.getUserId(); + //2. token失效 + if (tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) { + throw new IncorrectCredentialsException("token失效,请重新登录"); + } + } + //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录 + Object user = shiroService.findByUserId(userId); + //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常 + if (user == null) { + throw new UnknownAccountException("用户不存在!"); + } + //5. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo + return new SimpleAuthenticationInfo(user, accessToken, this.getName()); + } + + @Override + public boolean supports(AuthenticationToken authenticationToken) { + return authenticationToken instanceof AuthToken; + } + +} + diff --git a/src/main/java/com/common/base/shiro/ShiroConfig.java b/src/main/java/com/common/base/shiro/ShiroConfig.java new file mode 100644 index 0000000..5603865 --- /dev/null +++ b/src/main/java/com/common/base/shiro/ShiroConfig.java @@ -0,0 +1,91 @@ +package com.common.base.shiro; + +import com.common.base.shiro.service.SystemRealm; +import com.common.base.utils.SpringContextUtil; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.servlet.Filter; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +@Configuration +public class ShiroConfig { + + @Autowired + SystemRealm systemRealm; + + /** + * 不加这个注解不生效,具体不详 + */ + @Bean + @ConditionalOnMissingBean + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { + DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); + defaultAAP.setProxyTargetClass(true); + return defaultAAP; + } + + /** + * 将自己的验证方式加入容器 + */ + @Bean + public CustomRealm myShiroRealm() { + return new CustomRealm(); + } + + /** + * 权限管理,配置主要是Realm的管理认证 + */ + @Bean("securityManager") + public SecurityManager securityManager() { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + securityManager.setRealm(myShiroRealm()); + return securityManager; + } + + + /** + * Filter工厂,设置对应的过滤条件和跳转条件 + */ + @Bean("shiroFilter") + public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { + ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); + shiroFilterFactoryBean.setSecurityManager(securityManager); + Map filters = new HashMap<>(); + filters.put("auth", new AuthFilter()); + shiroFilterFactoryBean.setFilters(filters); + shiroFilterFactoryBean.setFilters(filters); + shiroFilterFactoryBean.setFilterChainDefinitionMap(systemRealm.setShiroUrl()); + return shiroFilterFactoryBean; + } + + /** + * 加入注解的使用,不加入这个注解不生效 + */ + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); + authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); + return authorizationAttributeSourceAdvisor; + } + + @Bean + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } +} diff --git a/src/main/java/com/common/base/shiro/service/ShiroService.java b/src/main/java/com/common/base/shiro/service/ShiroService.java new file mode 100644 index 0000000..607e991 --- /dev/null +++ b/src/main/java/com/common/base/shiro/service/ShiroService.java @@ -0,0 +1,19 @@ +package com.common.base.shiro.service; + + +import com.common.base.common.ResultVO; +import com.common.base.entity.FtToken; + +/** + * @author lhc + */ +public interface ShiroService { + + ResultVO createToken(String userId); + + ResultVO logout(String accessToken); + + FtToken findByToken(String accessToken); + + Object findByUserId(String userId); +} diff --git a/src/main/java/com/common/base/shiro/service/ShiroServiceImpl.java b/src/main/java/com/common/base/shiro/service/ShiroServiceImpl.java new file mode 100644 index 0000000..5ea7b23 --- /dev/null +++ b/src/main/java/com/common/base/shiro/service/ShiroServiceImpl.java @@ -0,0 +1,144 @@ +package com.common.base.shiro.service; + +import com.common.base.common.ResultVO; +import com.common.base.common.ServiceException; +import com.common.base.dao.FtTokenDao; +import com.common.base.entity.FtToken; +import com.common.base.utils.RedisUtil; +import com.common.base.utils.TokenProccessor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import javax.annotation.Resource; +import java.util.*; + +/** + * @author lhc + */ +@Service +public class ShiroServiceImpl implements ShiroService { + + /** + * 用户失效时间 + */ + private static int EXPIRE; + + @Value("${login-time-out}") + public void setHost(int hours) { + ShiroServiceImpl.EXPIRE = hours * 3600 * 1000; + } + + + @Resource + FtTokenDao tokenMapper; + + @Resource + RedisUtil redisUtil; + + @Resource + SystemRealm systemRealm; + + @Override + /** 重点!! + * 生成一个token + *@param [userId] + *@return Result + */ + public ResultVO createToken(String userId) { + Map result = new HashMap<>(); + TokenProccessor tokenProccessor = TokenProccessor.getInstance(); + //生成一个token + String token = tokenProccessor.makeToken(); + //当前时间 + Date now = new Date(); + //过期时间 + Date expireTime = new Date(now.getTime() + EXPIRE); + FtToken tokenEntity = new FtToken(); + // 是否使用redis存入token + if (RedisUtil.isUseful) { + boolean flag = redisUtil.hset("session", String.valueOf(userId), token,EXPIRE / 1000); + if (flag) { + Map map = new HashMap<>(); + map.put("userId", userId); + map.put("expireTime",expireTime); + flag = redisUtil.hmset(token, map, EXPIRE / 1000); + if (!flag) { + throw new ServiceException("登陆失败"); + } + } else { + throw new ServiceException("登陆失败"); + } + } else { + tokenEntity.setUserId(userId); + //判断是否生成过token + tokenEntity = tokenMapper.selectOne(tokenEntity); + if (tokenEntity == null) { + tokenEntity = new FtToken(); + tokenEntity.setUserId(userId); + tokenEntity.setToken(token); + tokenEntity.setUpdateTime(now); + tokenEntity.setExpireTime(expireTime); + //保存token + tokenMapper.insertSelective(tokenEntity); + } else { + tokenEntity.setToken(token); + tokenEntity.setUpdateTime(now); + tokenEntity.setExpireTime(expireTime); + //更新token + int i = tokenMapper.updateByPrimaryKey(tokenEntity); + } + } + //返回token给前端 + result.put("token", token); + result.put("expire", expireTime); + return ResultVO.getSuccess(result); + } + + @Override + public ResultVO logout(String accessToken) { + if (RedisUtil.isUseful) { + Map map = redisUtil.hmget(accessToken); + Integer userId = (Integer) map.get("userId"); + redisUtil.del(accessToken); + redisUtil.hdel("session", String.valueOf(userId)); + return ResultVO.getSuccess(); + } else { + //生成一个token + TokenProccessor tokenProccessor = TokenProccessor.getInstance(); + //生成一个token + String token = tokenProccessor.makeToken(); + //修改token + FtToken tokenEntity = new FtToken(); + tokenEntity.setToken(token); + Example example = new Example(FtToken.class); + example.createCriteria().andEqualTo("token", accessToken); + int i = tokenMapper.updateByExampleSelective(tokenEntity, example); + if (i == 1) { + return ResultVO.getSuccess(); + } else { + throw new ServiceException("退出失败"); + } + } + } + + @Override + public FtToken findByToken(String accessToken) { + FtToken osToken = new FtToken(); + osToken.setToken(accessToken); + return tokenMapper.selectOne(osToken); + } + + @Override + public Object findByUserId(String userId) { + return systemRealm.findByUserId(userId); + } + + public static void main(String[] args) { + ServiceLoader loader = ServiceLoader.load(ShiroService.class); + Iterator iterator = loader.iterator(); + iterator.next(); + } +} + + diff --git a/src/main/java/com/common/base/shiro/service/ShiroType.java b/src/main/java/com/common/base/shiro/service/ShiroType.java new file mode 100644 index 0000000..46a097a --- /dev/null +++ b/src/main/java/com/common/base/shiro/service/ShiroType.java @@ -0,0 +1,7 @@ +package com.common.base.shiro.service; + +public class ShiroType { + + public static final String AUTH = "auth"; + public static final String ANON = "anon"; +} diff --git a/src/main/java/com/common/base/shiro/service/SystemRealm.java b/src/main/java/com/common/base/shiro/service/SystemRealm.java new file mode 100644 index 0000000..e7a2cd2 --- /dev/null +++ b/src/main/java/com/common/base/shiro/service/SystemRealm.java @@ -0,0 +1,41 @@ +package com.common.base.shiro.service; + + +import com.common.base.entity.FtToken; +import org.apache.shiro.authz.SimpleAuthorizationInfo; + +import java.util.LinkedHashMap; + +/** + * @author lhc + * @date 2020-07-28 + * @descirption 系统realm权限设置接口 + */ +public interface SystemRealm { + + /** + * 获取权限注入接口 + * @param user 用户信息 + * @return shiro权限注入对象 + */ + SimpleAuthorizationInfo setAuthoriztion(Object user); + + /** + * 获取用户信息 + * @param userId 用户标识 + * @return 用户信息 + */ + Object findByUserId(String userId); + + /** + * 设置Shiro访问的url + * @return urlMap + */ + LinkedHashMap setShiroUrl(); + + /** + * 设置Shiro的token + * @return token + */ + FtToken setShiroToken(); +} diff --git a/src/main/java/com/common/base/utils/DateUtil.java b/src/main/java/com/common/base/utils/DateUtil.java new file mode 100644 index 0000000..e7f118e --- /dev/null +++ b/src/main/java/com/common/base/utils/DateUtil.java @@ -0,0 +1,84 @@ +package com.common.base.utils; + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; + +public class DateUtil { + + + /** + * 日期格式化成字符串 + * @param date + * @param format + * @return + */ + public static String DateFormat(Date date,String format) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDateTime date1 = date2LocalDateTime(date); + return date1.format(dtf); + } + + /** + * 字符串格式化成日期 + */ + public static Date StringFormat(String string,String format) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDate localDate = LocalDate.parse(string,dtf); + return localDate2Date(localDate); + } + + + /** + * Date转换为LocalDateTime + * @param date + */ + public static LocalDateTime date2LocalDateTime(Date date){ + Instant instant = date.toInstant();//An instantaneous point on the time-line.(时间线上的一个瞬时点。) + ZoneId zoneId = ZoneId.systemDefault();//A time-zone ID, such as {@code Europe/Paris}.(时区) + return instant.atZone(zoneId).toLocalDateTime(); + } + + /** + * LocalDateTime转换为Date + * @param localDateTime + */ + public static Date localDateTime2Date( LocalDateTime localDateTime){ + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zdt = localDateTime.atZone(zoneId);//Combines this date-time with a time-zone to create a ZonedDateTime. + return Date.from(zdt.toInstant()); + } + + /** + * localDate转Date + */ + public static Date localDate2Date(LocalDate localDate) { + ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault()); + Instant instant1 = zonedDateTime.toInstant(); + return Date.from(instant1); + } + + /** + * Date 转 localDate + */ + public static LocalDate date2LocalDate(Date date) { + Instant instant = date.toInstant(); + ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault()); + return zdt.toLocalDate(); + } + + /** + * 获取字符串中的月份 + * @param str + * @param format + * @return + */ + public static int getStringMonth(String str,String format) { + Date date=StringFormat(str, format); + Calendar cal=Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.MONTH); + } + +} diff --git a/src/main/java/com/common/base/utils/EncryptUtil.java b/src/main/java/com/common/base/utils/EncryptUtil.java new file mode 100644 index 0000000..aff3f83 --- /dev/null +++ b/src/main/java/com/common/base/utils/EncryptUtil.java @@ -0,0 +1,320 @@ +package com.common.base.utils; + +import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.SecureRandom; + +public class EncryptUtil { + public static final String MD5 = "MD5"; + public static final String SHA1 = "SHA1"; + public static final String HmacMD5 = "HmacMD5"; + public static final String HmacSHA1 = "HmacSHA1"; + public static final String DES = "DES"; + public static final String AES = "AES"; + + /** + * 编码格式;默认使用uft-8 + */ + public String charset = "utf-8"; + /** + * DES + */ + public int keysizeDES = 0; + /** + * AES + */ + public int keysizeAES = 128; + + public static EncryptUtil me; + + private EncryptUtil() { + //单例 + } + + //双重锁 + public static EncryptUtil getInstance() { + if (me == null) { + synchronized (EncryptUtil.class) { + if (me == null) { + me = new EncryptUtil(); + } + } + } + return me; + } + + /** + * 使用MessageDigest进行单向加密(无密码) + * + * @param res 被加密的文本 + * @param algorithm 加密算法名称 + * @return + */ + private String messageDigest(String res, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return base64(md.digest(resBytes)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator进行单向/双向加密(可设密码) + * + * @param res 被加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密使用的秘钥 + * @return + */ + private String keyGeneratorMac(String res, String algorithm, String key) { + try { + SecretKey sk = null; + if (key == null) { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + sk = kg.generateKey(); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + sk = new SecretKeySpec(keyBytes, algorithm); + } + Mac mac = Mac.getInstance(algorithm); + mac.init(sk); + byte[] result = mac.doFinal(res.getBytes()); + return base64(result); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错 + * + * @param res 加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密的秘钥 + * @param keysize + * @param isEncode + * @return + */ + private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) { + try { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + if (keysize == 0) { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + kg.init(new SecureRandom(keyBytes)); + } else if (key == null) { + kg.init(keysize); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(keyBytes); + kg.init(keysize, secureRandom); + } + SecretKey sk = kg.generateKey(); + SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm); + Cipher cipher = Cipher.getInstance(algorithm); + if (isEncode) { + cipher.init(Cipher.ENCRYPT_MODE, sks); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return parseByte2HexStr(cipher.doFinal(resBytes)); + } else { + cipher.init(Cipher.DECRYPT_MODE, sks); + return new String(cipher.doFinal(parseHexStr2Byte(res))); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private String base64(byte[] res) { + return Base64.encode(res); + } + + /** + * 将二进制转换成16进制 + */ + public static String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /** + * 将16进制转换为二进制 + */ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) { + return null; + } + byte[] result = new byte[hexStr.length() / 2]; + for (int i = 0; i < hexStr.length() / 2; i++) { + int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); + int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String MD5(String res) { + return messageDigest(res, MD5); + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String MD5(String res, String key) { + return keyGeneratorMac(res, HmacMD5, key); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String SHA1(String res) { + return messageDigest(res, SHA1); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String SHA1(String res, String key) { + return keyGeneratorMac(res, HmacSHA1, key); + } + + /** + * 使用DES加密算法进行加密(可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String DESencode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, true); + } + + /** + * 对使用DES加密算法的密文进行解密(可逆) + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String DESdecode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, false); + } + + /** + * 使用AES加密算法经行加密(可逆) + * + * @param res 需要加密的密文 + * @param key 秘钥 + * @return + */ + public String AESencode(String res, String key) { + return keyGeneratorES(res, AES, key, keysizeAES, true); + } + + /** + * 对使用AES加密算法的密文进行解密 + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String AESdecode(String res, String key) { + return keyGeneratorES(res, AES, key, keysizeAES, false); + } + + /** + * 使用异或进行加密 + * + * @param res 需要加密的密文 + * @param key 秘钥 + * @return + */ + public String XORencode(String res, String key) { + byte[] bs = res.getBytes(); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return parseByte2HexStr(bs); + } + + /** + * 使用异或进行解密 + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String XORdecode(String res, String key) { + byte[] bs = parseHexStr2Byte(res); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return new String(bs); + } + + /** + * 直接使用异或(第一调用加密,第二次调用解密) + * + * @param res 密文 + * @param key 秘钥 + * @return + */ + public int XOR(int res, String key) { + return res ^ key.hashCode(); + } + + /** + * 使用Base64进行加密 + * + * @param res 密文 + * @return + */ + public String Base64Encode(String res) { + return Base64.encode(res.getBytes()); + } + + /** + * 使用Base64进行解密 + * + * @param res + * @return + */ + public String Base64Decode(String res) { + return new String(Base64.decode(res)); + } +} diff --git a/src/main/java/com/common/base/utils/HttpClient.java b/src/main/java/com/common/base/utils/HttpClient.java new file mode 100644 index 0000000..c74ae9c --- /dev/null +++ b/src/main/java/com/common/base/utils/HttpClient.java @@ -0,0 +1,86 @@ +package com.common.base.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +public class HttpClient { + + + //连接超时时间 + private static final int CONNECTION_TIME_OUT = 30000; + + //读取超时时间 + private static final int READ_TIME_OUT = 30000; + + /** + * post方法接口 + * @param targetUrl---访问的接口网址 + * @param map----携带的参数 + * @return + */ + public static Map postMethod(String targetUrl, Map map){ + //兑换带ticket的url + String urlPath = targetUrl; + // 发送请求 + JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map)); + JSONArray jsonArray1 = new JSONArray(); + Map map2 = HttpClient.getCasUtils(jsonObject, jsonArray1, ""); + RestTemplate restTemplate = (RestTemplate) map2.get("restTemplate"); + HttpEntity httprequest = (HttpEntity) map2.get("httprequest"); + String response = restTemplate.postForObject(urlPath, httprequest, String.class); + JSONObject jsonObject1 = JSON.parseObject(response); + Map resultMap = JSONObject.toJavaObject(jsonObject1, Map.class); + return resultMap; + } + + /** + * get方法 + * @param targetUrl---目标地址 + * @param itemMap----传入参数 + * @return + */ + public static Map getMethod(String targetUrl,Map itemMap){ + String url = targetUrl; + JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(itemMap)); + JSONArray jsonArray = new JSONArray(); + Map map = HttpClient.getCasUtils(jsonObject,jsonArray,""); + RestTemplate restTemplate = (RestTemplate) map.get("restTemplate"); + String response=restTemplate.getForEntity(url,String.class).getBody(); + JSONObject result = JSON.parseObject(response); + Map resultMap = JSONObject.toJavaObject(result, Map.class); + return resultMap; + } + + public static Map getCasUtils(JSONObject jsonObject, JSONArray jsonArray, String str){ + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + requestFactory.setConnectTimeout(CONNECTION_TIME_OUT); + requestFactory.setReadTimeout(READ_TIME_OUT); + RestTemplate restTemplate = new RestTemplate(requestFactory); + // 参数 + HttpHeaders headers = new HttpHeaders(); + MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); + headers.setContentType(type); + headers.add("Accept", MediaType.APPLICATION_JSON.toString()); + HttpEntity httprequest= null; + if (jsonObject.isEmpty()&&!jsonArray.isEmpty()) { + httprequest = new HttpEntity(jsonArray.toJSONString(), headers); + } else if (jsonArray.isEmpty() && !jsonObject.isEmpty()) { + httprequest = new HttpEntity(jsonObject.toJSONString(), headers); + } else { + httprequest = new HttpEntity(str, headers); + } + Map map = new HashMap<>(); + map.put("restTemplate", restTemplate); + map.put("httprequest", httprequest); + return map; + } +} diff --git a/src/main/java/com/common/base/utils/ListUtil.java b/src/main/java/com/common/base/utils/ListUtil.java new file mode 100644 index 0000000..9b77ad8 --- /dev/null +++ b/src/main/java/com/common/base/utils/ListUtil.java @@ -0,0 +1,23 @@ +package com.common.base.utils; + + +import com.common.base.common.ServiceException; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ListUtil { + + public static Map getValue(String value, List> list,String key) { + Optional> objectMap = list + .stream() + .filter(r -> (Integer) r.get(key) == Integer.parseInt(value)) + .findFirst(); + if (objectMap.isPresent()) { + return objectMap.get(); + } else { + throw new ServiceException("key值不存在"); + } + } +} diff --git a/src/main/java/com/common/base/utils/MD5Util.java b/src/main/java/com/common/base/utils/MD5Util.java new file mode 100644 index 0000000..a60445c --- /dev/null +++ b/src/main/java/com/common/base/utils/MD5Util.java @@ -0,0 +1,19 @@ +package com.common.base.utils; + +import org.springframework.util.DigestUtils; + +public class MD5Util { + + public static String setMd5(String password){ + return DigestUtils.md5DigestAsHex(password.getBytes()); + } + + public static boolean isEqual(String password, String md5) { + String str = DigestUtils.md5DigestAsHex(password.getBytes()); + if (md5.equals(str)) { + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/com/common/base/utils/MailAuthenticator.java b/src/main/java/com/common/base/utils/MailAuthenticator.java new file mode 100644 index 0000000..471dd69 --- /dev/null +++ b/src/main/java/com/common/base/utils/MailAuthenticator.java @@ -0,0 +1,21 @@ +package com.common.base.utils; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +public class MailAuthenticator extends Authenticator{ + String userName=null; + String password=null; + + public MailAuthenticator(){ + } + public MailAuthenticator(String username, String password) { + this.userName = username; + this.password = password; + } + @Override + protected PasswordAuthentication getPasswordAuthentication(){ + return new PasswordAuthentication(userName, password); + } + +} diff --git a/src/main/java/com/common/base/utils/MailBean.java b/src/main/java/com/common/base/utils/MailBean.java new file mode 100644 index 0000000..8eb0fc5 --- /dev/null +++ b/src/main/java/com/common/base/utils/MailBean.java @@ -0,0 +1,98 @@ +package com.common.base.utils; + +import java.util.List; +import java.util.Properties; + +public class MailBean { + // 发送邮件的服务器的IP和端口 + private String mailServerHost; + private String mailServerPort = "25"; + // 邮件发送者的地址 + private String fromAddress; + // 邮件接收者的地址 + private List toAddress; + // 登陆邮件发送服务器的用户名和密码 + private String userName; + private String password; + // 是否需要身份验证 + private boolean validate = false; + // 邮件主题 + private String subject; + // 邮件的文本内容 + private String content; + // 邮件附件的文件名 + private List attachFileNames; + /** + * 获得邮件会话属性 + */ + + public Properties getProperties(){ + Properties p = new Properties(); + p.put("mail.smtp.host", this.mailServerHost); + p.put("mail.smtp.port", this.mailServerPort); + p.put("mail.smtp.auth", validate ? "true" : "false"); + p.put("mail.mime.address.strict", "false"); + return p; + } + public String getMailServerHost() { + return mailServerHost; + } + public void setMailServerHost(String mailServerHost) { + this.mailServerHost = mailServerHost; + } + public String getMailServerPort() { + return mailServerPort; + } + public void setMailServerPort(String mailServerPort) { + this.mailServerPort = mailServerPort; + } + public String getFromAddress() { + return fromAddress; + } + public void setFromAddress(String fromAddress) { + this.fromAddress = fromAddress; + } + + public List getToAddress() { + return toAddress; + } + public void setToAddress(List toAddress) { + this.toAddress = toAddress; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public boolean isValidate() { + return validate; + } + public void setValidate(boolean validate) { + this.validate = validate; + } + public String getSubject() { + return subject; + } + public void setSubject(String subject) { + this.subject = subject; + } + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public List getAttachFileNames() { + return attachFileNames; + } + public void setAttachFileNames(List attachFileNames) { + this.attachFileNames = attachFileNames; + } +} diff --git a/src/main/java/com/common/base/utils/MailOperate.java b/src/main/java/com/common/base/utils/MailOperate.java new file mode 100644 index 0000000..3cf1a93 --- /dev/null +++ b/src/main/java/com/common/base/utils/MailOperate.java @@ -0,0 +1,142 @@ +package com.common.base.utils; + + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.mail.*; +import javax.mail.internet.*; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +public class MailOperate { + /** + * 以文本格式发送邮件 + * @param mailInfo 待发送的邮件的信息 + */ + public boolean sendTextMail(MailBean mailInfo) { + // 判断是否需要身份认证 + MailAuthenticator authenticator = null; + Properties pro = mailInfo.getProperties(); + if (mailInfo.isValidate()) { + // 如果需要身份认证,则创建一个密码验证器 + authenticator = new MailAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); + } + // 根据邮件会话属性和密码验证器构造一个发送邮件的session + Session sendMailSession = Session.getDefaultInstance(pro,authenticator); + try { + // 根据session创建一个邮件消息 + Message mailMessage = new MimeMessage(sendMailSession); + // 创建邮件发送者地址 + Address from = new InternetAddress(mailInfo.getFromAddress()); + // 设置邮件消息的发送者 + mailMessage.setFrom(from); + // 创建邮件的接收者地址,并设置到邮件消息中 + List toAddress=null; + if(mailInfo.getToAddress().size()>1){ + toAddress=mailInfo.getToAddress(); + Address[] address =new InternetAddress[toAddress.size()]; + for (int i = 0; i < toAddress.size(); i++) { + address[i]=new InternetAddress(toAddress.get(i)); + } + mailMessage.setRecipients(Message.RecipientType.TO,address); + }else{ + toAddress=mailInfo.getToAddress(); + Address to = new InternetAddress(toAddress.get(0)); + // Message.RecipientType.TO属性表示接收者的类型为TO + mailMessage.setRecipient(Message.RecipientType.TO,to); + } + // 设置邮件消息的主题 + mailMessage.setSubject(mailInfo.getSubject()); + // 设置邮件消息发送的时间 + mailMessage.setSentDate(new Date()); + // 设置邮件消息的主要内容 + String mailContent = mailInfo.getContent(); + mailMessage.setText(mailContent); + // 发送邮件 + Transport.send(mailMessage); + return true; + } catch (MessagingException ex) { +// ex.printStackTrace(); + return false; + } +// return false; + } + + /** + * 以HTML格式发送邮件 + * @param mailInfo 待发送的邮件信息 + * @throws UnsupportedEncodingException + */ + public static boolean sendHtmlMail(MailBean mailInfo) throws UnsupportedEncodingException{ + // 判断是否需要身份认证 + MailAuthenticator authenticator = null; + Properties pro = mailInfo.getProperties(); + //如果需要身份认证,则创建一个密码验证器 + if (mailInfo.isValidate()) { + authenticator = new MailAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); + } + // 根据邮件会话属性和密码验证器构造一个发送邮件的session + Session sendMailSession = Session.getInstance(pro,authenticator); + + try { + // 根据session创建一个邮件消息 + Message mailMessage = new MimeMessage(sendMailSession); + // 创建邮件发送者地址 + Address from = new InternetAddress(mailInfo.getFromAddress()); + // 设置邮件消息的发送者 + mailMessage.setFrom(from); + // 创建邮件的接收者地址,并设置到邮件消息中 + List toAddress=null; + if(mailInfo.getToAddress().size()>1){ + toAddress=mailInfo.getToAddress(); + Address[] address =new InternetAddress[toAddress.size()]; + for (int i = 0; i < toAddress.size(); i++) { + address[i]=new InternetAddress(toAddress.get(i)); + } + mailMessage.setRecipients(Message.RecipientType.TO,address); + }else{ + toAddress=mailInfo.getToAddress(); + Address to = new InternetAddress(toAddress.get(0)); + // Message.RecipientType.TO属性表示接收者的类型为TO + mailMessage.setRecipient(Message.RecipientType.TO,to); + } + + // 设置邮件消息的主题 + mailMessage.setSubject(mailInfo.getSubject()); + // 设置邮件消息发送的时间 + mailMessage.setSentDate(new Date()); + // MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象 + Multipart mainPart = new MimeMultipart(); + // 创建一个包含HTML内容的MimeBodyPart + BodyPart html = new MimeBodyPart(); + // 设置HTML内容 + html.setContent(mailInfo.getContent(), "text/html; charset=utf-8"); + mainPart.addBodyPart(html); + if(mailInfo.getAttachFileNames()!=null){ + List attachFileNames = mailInfo.getAttachFileNames(); + for (String path : attachFileNames) { + html=new MimeBodyPart(); + FileDataSource fds=new FileDataSource(path); //得到数据源 + html.setDataHandler(new DataHandler(fds)); //得到附件本身并至入BodyPart + //此处是为了解决附件中文名乱码的问题 + String fileName= MimeUtility.encodeText(fds.getName()); + html.setFileName(fileName); //得到文件名同样至入BodyPart + mainPart.addBodyPart(html); + } + } + + // 将MiniMultipart对象设置为邮件内容 + mailMessage.setContent(mainPart); + // 发送邮件 + Transport.send(mailMessage); + return true; + } catch (MessagingException ex) { + ex.printStackTrace(); + } + return false; + } + + +} diff --git a/src/main/java/com/common/base/utils/RandomUtil.java b/src/main/java/com/common/base/utils/RandomUtil.java new file mode 100644 index 0000000..bc354cb --- /dev/null +++ b/src/main/java/com/common/base/utils/RandomUtil.java @@ -0,0 +1,18 @@ +package com.common.base.utils; + +import java.util.Random; + +public class RandomUtil { + + + public static String getrandom() { + StringBuilder code = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 6; i++) { + int r = random.nextInt(10); + code.append(r); + } + return code.toString(); + + } +} diff --git a/src/main/java/com/common/base/utils/RedisUtil.java b/src/main/java/com/common/base/utils/RedisUtil.java new file mode 100644 index 0000000..0674480 --- /dev/null +++ b/src/main/java/com/common/base/utils/RedisUtil.java @@ -0,0 +1,584 @@ +package com.common.base.utils; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; + + +/** + * Redis工具类 + */ + +@Component +public final class RedisUtil { + + // url + public static boolean isUseful; + + // 通过yml文件获取host + @Value("${isRedisLogin}") + public void setHost(boolean isUseful) { + RedisUtil.isUseful = isUseful; + } + + private final static Logger logger = LoggerFactory.getLogger(RedisUtil.class); + + @Resource + private RedisTemplate redisTemplate; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete(CollectionUtils.arrayToList(key)); + } + } + } + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + +} diff --git a/src/main/java/com/common/base/utils/RegexUtil.java b/src/main/java/com/common/base/utils/RegexUtil.java new file mode 100644 index 0000000..e9bd7ae --- /dev/null +++ b/src/main/java/com/common/base/utils/RegexUtil.java @@ -0,0 +1,11 @@ +package com.common.base.utils; + +import java.util.regex.Pattern; + +public class RegexUtil { + + public static boolean isChinese(String str) { + String pattern = "^([\\u4E00-\\u9FA5])*$"; + return Pattern.matches(pattern, str); + } +} diff --git a/src/main/java/com/common/base/utils/SpringContextUtil.java b/src/main/java/com/common/base/utils/SpringContextUtil.java new file mode 100644 index 0000000..796467e --- /dev/null +++ b/src/main/java/com/common/base/utils/SpringContextUtil.java @@ -0,0 +1,26 @@ +package com.common.base.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +public class SpringContextUtil { + private static ApplicationContext applicationContext; + //获取上下文 + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + //设置上下文 + public static void setApplicationContext(ApplicationContext applicationContext) { + SpringContextUtil.applicationContext = applicationContext; + } + //通过名字获取上下文中的bean + public static Object getBean(String name){ + return applicationContext.getBean(name); + } + //通过类型获取上下文中的bean + public static Object getBean(Class requiredType){ + return applicationContext.getBean(requiredType); + } +} diff --git a/src/main/java/com/common/base/utils/TokenProccessor.java b/src/main/java/com/common/base/utils/TokenProccessor.java new file mode 100644 index 0000000..8764cef --- /dev/null +++ b/src/main/java/com/common/base/utils/TokenProccessor.java @@ -0,0 +1,33 @@ +package com.common.base.utils; + +import java.util.Random; + +/** + * 生成Token的工具类 + * + */ +public class TokenProccessor { + + private TokenProccessor(){} + + private static final TokenProccessor instance = new TokenProccessor(); + + public static TokenProccessor getInstance() { + return instance; + } + + /** + * 生成Token + * @return + */ + public String makeToken() { + String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + ""; + EncryptUtil encryptUtil = EncryptUtil.getInstance(); + String str = encryptUtil.MD5(token); + str = str.replaceAll("/", ""); + str = str.replaceAll("\\+", ""); + str = str.replaceAll("=", ""); + return str; + } + +} diff --git a/src/main/java/com/common/base/utils/UserInfoUtil.java b/src/main/java/com/common/base/utils/UserInfoUtil.java new file mode 100644 index 0000000..d3f9984 --- /dev/null +++ b/src/main/java/com/common/base/utils/UserInfoUtil.java @@ -0,0 +1,46 @@ +package com.common.base.utils; + +import com.common.base.entity.FtToken; +import com.common.base.shiro.service.ShiroService; +import org.apache.shiro.SecurityUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; + +@Component +public class UserInfoUtil { + + @Resource + ShiroService shiroService; + + /** + * 通过request返回用户信息 + * @param request request + * @return 用户类型 + */ + public T getUserInfoByRequest(HttpServletRequest request) { + String token = request.getHeader("X-Access-Token"); + if (StringUtils.isEmpty(token)) { + return null; + } + FtToken ftToken = shiroService.findByToken(token); + Date expireData= ftToken.getExpireTime(); + Date date = new Date(); + if (date.getTime() > expireData.getTime()) { + return null; + } + return (T) shiroService.findByUserId(ftToken.getUserId()); + } + + /** + * 获取当前用户信息 + * @param 用户实体类泛型 + * @return 返回结果 + */ + public static T getUserInfo(){ + return (T)SecurityUtils.getSubject().getPrincipal(); + } +} diff --git a/src/main/java/com/common/base/utils/XssClass.java b/src/main/java/com/common/base/utils/XssClass.java new file mode 100644 index 0000000..e0d159c --- /dev/null +++ b/src/main/java/com/common/base/utils/XssClass.java @@ -0,0 +1,18 @@ +package com.common.base.utils; + +import static org.thymeleaf.util.StringUtils.split; + +public class XssClass { + + public static boolean sqlInj(String str){ + String injStr = "'|and|exec|insert|select|delete|update|"+ + "count|*|%|chr|mid|master|truncate|char|declare|;|or|+|,|