### 统一工具类的意义 api-commons帮助我们简化每一行代码,减少每一个方法,然代码可读性、容错性更高。 提供数据源切换功能,日志记录功能,获取当前用户功能,oauth白名单功能。 另外集成Hutool,完整文档查看[hutool-doc](https://hutool.cn/docs)。 ### hutool 提供类哪些功能 一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件: * hutool-aop JDK动态代理封装,提供非IOC下的切面支持 * hutool-bloomFilter 布隆过滤,提供一些Hash算法的布隆过滤 * hutool-cache 缓存 * hutool-core 核心,包括Bean操作、日期、各种Util等 * hutool-cron 定时任务模块,提供类Crontab表达式的定时任务 * hutool-crypto 加密解密模块 * hutool-db JDBC封装后的数据操作,基于ActiveRecord思想 * hutool-dfa 基于DFA模型的多关键字查找 * hutool-extra 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码等) * hutool-http 基于HttpUrlConnection的Http客户端封装 * hutool-log 自动识别日志实现的日志门面 * hutool-script 脚本执行封装,例如Javascript * hutool-setting 功能更强大的Setting配置文件和Properties封装 * hutool-system 系统参数调用封装(JVM信息等) * hutool-json JSON实现 * hutool-captcha 图片验证码实现 * hutool-poi 针对POI中Excel的封装 可以根据需求对每个模块单独引入,也可以通过引入hutool-all方式引入所有模块。 api-commons代码清单 **日志工具类** ``` @Aspect @Order(-1) // 保证该AOP在@Transactional之前执行 public class LogAnnotationAspect { private static final Logger logger = LoggerFactory.getLogger(LogAnnotationAspect.class); @Around("@annotation(ds)") public Object logSave(ProceedingJoinPoint joinPoint, LogAnnotation ds) throws Throwable { // 请求流水号 String transid = getRandom(); // 记录开始时间 long start = System.currentTimeMillis(); // 获取方法参数 String url = null; String httpMethod = null; Object result = null; List<Object> httpReqArgs = new ArrayList<Object>(); SysLog log = new SysLog(); log.setCreateTime(new Date()); LoginAppUser loginAppUser = SysUserUtil.getLoginAppUser(); if (loginAppUser != null) { log.setUsername(loginAppUser.getUsername()); } MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class); log.setModule(logAnnotation.module() + ":" + methodSignature.getDeclaringTypeName() + "/" + methodSignature.getName()); Object[] args = joinPoint.getArgs();// 参数值 url = methodSignature.getDeclaringTypeName() + "/"+ methodSignature.getName(); for (Object object : args) { if (object instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) object; url = request.getRequestURI(); httpMethod = request.getMethod(); } else if (object instanceof HttpServletResponse) { } else { httpReqArgs.add(object); } } try { String params = JSONObject.toJSONString(httpReqArgs); log.setParams(params); // 打印请求参数参数 logger.info("开始请求,transid={}, url={} , httpMethod={}, reqData={} ", transid, url, httpMethod, params); } catch (Exception e) { logger.error("记录参数失败:{}", e.getMessage()); } try { // 调用原来的方法 result = joinPoint.proceed(); log.setFlag(Boolean.TRUE); } catch (Exception e) { log.setFlag(Boolean.FALSE); log.setRemark(e.getMessage()); throw e; } finally { CompletableFuture.runAsync(() -> { try { if (logAnnotation.recordRequestParam()) { LogService logService = SpringUtils.getBean(LogServiceImpl.class); logService.save(log); } } catch (Exception e) { logger.error("记录参数失败:{}", e.getMessage()); } }); // 获取回执报文及耗时 logger.info("请求完成, transid={}, 耗时={}, resp={}:", transid, (System.currentTimeMillis() - start), result == null ? null : JSON.toJSONString(result)); } return result; } /** * 生成日志随机数 * * @return */ public String getRandom() { int i = 0; StringBuilder st = new StringBuilder(); while (i < 5) { i++; st.append(ThreadLocalRandom.current().nextInt(10)); } return st.toString() + System.currentTimeMillis(); } } ``` **多数据源工具类** ``` /** * 切换数据源Advice */ @Aspect @Order(-1) // 保证该AOP在@Transactional之前执行 public class DataSourceAspect { private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class); @Before("@annotation(ds)") public void changeDataSource(JoinPoint point, DataSource ds) throws Throwable { String dsId = ds.name(); try { DataSourceKey dataSourceKey = DataSourceKey.valueOf(dsId); DataSourceHolder.setDataSourceKey(dataSourceKey); } catch (Exception e) { logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature()); } } @After("@annotation(ds)") public void restoreDataSource(JoinPoint point, DataSource ds) { logger.debug("Revert DataSource : {transIdo} > {}", ds.name(), point.getSignature()); DataSourceHolder.clearDataSourceKey(); } } ``` **分页工具类** ``` /** * @author 作者 owen E-mail: 624191343@qq.com * @version 创建时间:2017年11月12日 上午22:57:51 * 分页实体类 * total 总数 * code 是否成功 * data 当前页结果集 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class PageResult<T> implements Serializable { private static final long serialVersionUID = -275582248840137389L; private Long count; private int code; private List<T> data; } ``` **oauth认证成功后获取用户信息工具类** ``` /** * @author 作者 owen E-mail: 624191343@qq.com * @version 创建时间:2017年11月12日 上午22:57:51 * 用户实体绑定spring security */ @Getter @Setter public class LoginAppUser extends SysUser implements UserDetails { /** * */ private static final long serialVersionUID = -3685249101751401211L; private Set<SysRole> sysRoles; private Set<String> permissions; /*** * 权限重写 */ @JsonIgnore @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> collection = new HashSet<>(); if (!CollectionUtils.isEmpty(sysRoles)) { sysRoles.parallelStream().forEach(role -> { if (role.getCode().startsWith("ROLE_")) { collection.add(new SimpleGrantedAuthority(role.getCode())); } else { collection.add(new SimpleGrantedAuthority("ROLE_" + role.getCode())); } }); } if (!CollectionUtils.isEmpty(permissions)) { permissions.parallelStream().forEach(per -> { collection.add(new SimpleGrantedAuthority(per)); }); } return collection; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return getEnabled(); } } ``` **认证授权白名单配置** ``` /** * @author 作者 owen E-mail: 624191343@qq.com * @version 创建时间:2017年11月12日 上午22:57:51 url白名单处理 application.yml中配置需要放权的url白名单 */ //@ConfigurationProperties(prefix = "permit") @ConfigurationProperties(prefix = "security.oauth2") public class PermitUrlProperties { /** * 监控中心和swagger需要访问的url */ private static final String[] ENDPOINTS = { "/**/actuator/health", "/**/actuator/env", "/**/actuator/metrics/**", "/**/actuator/trace", "/**/actuator/dump", "/**/actuator/jolokia", "/**/actuator/info", "/**/actuator/logfile", "/**/actuator/refresh", "/**/actuator/flyway", "/**/actuator/liquibase", "/**/actuator/heapdump", "/**/actuator/loggers", "/**/actuator/auditevents", "/**/actuator/env/PID", "/**/actuator/jolokia/**", "/**/actuator/archaius/**", "/**/actuator/beans/**", "/**/actuator/httptrace", "/**/v2/api-docs/**", "/**/swagger-ui.html", "/**/swagger-resources/**", "/**/webjars/**", "/**/druid/**", "/**/actuator/hystrix.stream","/**/actuator/hystrix.stream**/**", "/**/turbine.stream", "/**/turbine.stream**/**", "/**/hystrix","/**/hystrix.stream", "/**/hystrix/**" ,"/**/hystrix/**/**" ,"/**/proxy.stream/**" ,"/**/favicon.ico" }; private String[] ignored; /** * 需要放开权限的url * * @param urls * 自定义的url * @return 自定义的url和监控中心需要访问的url集合 */ public String[] getIgnored() { if (ignored == null || ignored.length == 0) { return ENDPOINTS; } List<String> list = new ArrayList<>(); for (String url : ENDPOINTS) { list.add(url); } for (String url : ignored) { list.add(url); } return list.toArray(new String[list.size()]); } public void setIgnored(String[] ignored) { this.ignored = ignored; } } ```