开发Tips
2022/3/31 23:19:28
本文主要是介绍开发Tips,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
新项目开发小点
最近开了一个新项目,过程中解决了一些小问题,随手记录一下。
统一异常处理
后台出错时返回一个统一的结果,并把错误信息传到前端。
Spring AOP统一异常处理
/** * 统一异常处理 */ @ControllerAdvice public class ExceptionAdvice { private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class); @ExceptionHandler(Exception.class) @ResponseBody public BaseResponse handleException(Exception e) { logger.warn("接口出现异常", e); // 参数不正异常 if (e instanceof MissingServletRequestParameterException) { return new ResultResponse(ResultCode.ARGUMENT_ERROR, ResultCode.ARGUMENT_ERROR_MSG).setInfo(e.getMessage()); } // 请求方法不支持异常 if (e instanceof HttpRequestMethodNotSupportedException) { return new BaseResponse() .setCode(ResultCode.METHOD_NOT_SUPPORTED) .setMessage(ResultCode.METHOD_NOT_SUPPORTED_MSG); } return new ResultResponse() .setInfo(e.getMessage()) .setCode(ResultCode.FAIL) .setMessage("系统错误"); } }
Spring MVC 返回对象处理
返回的结果要加密处理result字段,原理同样是AOP
首先定义个注解表示哪些Controller要加密:
/** * 加密 ResultResponse 的 result 字段 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EncryptBody { }
再定义一个注解表示哪些方法不加密:
/** * 不加密 body 的方法 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface NotEncryptBody { }
然后是AOP处理类:
实现 ResponseBodyAdvice 接口
/** * 加密返回类型中的result字段 */ @Component //这个注解代表处理哪些 Controller,可以根据包名或注解控制,这里用了注解 @ControllerAdvice(annotations = EncryptBody.class) // 接口上的泛型代表方法的返回类型,一般来说 后端接口会有一个统一的返回类型 public class ResponseAdvice implements ResponseBodyAdvice<BaseResponse> { private static final Logger logger = LoggerFactory.getLogger(ResponseAdvice.class); // 决定方法是否处理 @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // 这里的逻辑是被 NotEncryptBody 的方法不处理 if (Arrays.stream(returnType.getMethodAnnotations()) .anyMatch(s -> s.annotationType().equals(NotEncryptBody.class))) { return false; } return true; } @Override public BaseResponse beforeBodyWrite(BaseResponse body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body == null) { final String msg = "返回 body 为 null"; logger.error(msg); return new ResultResponse() .setInfo(msg) .setCode(ResultCode.FAIL) .setMessage(ResultCode.FAIL_MSG); } if (body instanceof ResultResponse) { ResultResponse theRes = (ResultResponse) body; Object result = theRes.getResult(); if (result != null) { String toBeEncode = ""; if (result instanceof String) { toBeEncode = (String) result; } else { toBeEncode = JSON.toJSONString(result, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue); } // 试用sm4加密返回类型中的result字段 String encode = Sm4Util.encryptEcbDefault(toBeEncode); theRes.setResult(encode); return theRes; } } return body; } }
Json
Json 时间格式化
spring 默认使用的是jackson依赖,时间类型会有时区问题,在yml中使用如下配置解决:
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
如果使用fastjson,可以在实体类上标注如下注解:
@JSONField(format = "yyyy-MM-dd") private Date inputTime;
如果需要统一修改,直接修改公共变量JSON.DEFFAULT_DATE_FORMAT
Json 格式化泛型
调用他人接口时,别人装数据的字段不一定是什么值,这时就需要泛型
NucResDto<NucDataDto> dto = JSON.parseObject(json, new TypeReference<NucResDto<NucDataDto>>(){});
springboot mybatis-plus 整合
我接手项目的时候,没有用mybatis-plus,我直接加了进来。
添加依赖,然后修改注入 SqlSessionFactory 的方法。
主要是把
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
改为
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
同时设置主键策略(oracle数据库,主键试用序列):
// 设置 mybatis-plus 主键生成策略 GlobalConfig conf = new GlobalConfig(); List<IKeyGenerator> list = new ArrayList<>(1); list.add(new OracleKeyGenerator()); conf.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerators(list)); sessionFactory.setGlobalConfig(conf);
如果不是手动注入的 SqlSessionFactory 直接按照mybatis-plus 官方文档整合即可。
PageHelper 分页插件整合
整合mybatis-plus之后,添加分页插件依赖时需要排除Mybatis:
<!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.1</version> <exclusions> <exclusion> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </exclusion> <exclusion> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </exclusion> </exclusions> </dependency>
然后yml中配置:
# 分页插件配置 pagehelper: helper-dialect: oracle pageSizeZero: true params: count=countSql # 分页合理化,设置为true时,当前页大于总页数时会返回最后一页数据,并不需要这样因此设置为false reasonable: false support-methods-arguments: true
yml 配置转 Bean
@Component @ConfigurationProperties(prefix = "nucleate-config") public class NucleateConfig { }
此时IDEA会出现提醒(忘记什么提醒了)
去设置 -> Build, Exe... -> Compiler -> Annotation Processors 中 enable 一下就可以,这样yml中也不会报黄。
线程池工具类
有时候会在特定的调用点执行一些任务,就需要用线程池了。
线程池工具类
/** * 线程池工具类 */ public class ThreadPoolUtil { private static ThreadPoolExecutor threadPool; /** * 无返回值直接执行 * * @param runnable */ public static void execute(Runnable runnable) { getThreadPool().execute(runnable); } /** * 返回值直接执行 * * @param callable */ public static <T> Future<T> submit(Callable<T> callable) { return getThreadPool().submit(callable); } /** * 关闭线程池 */ public static void shutdown() { getThreadPool().shutdown(); } /** * dcs获取线程池 * * @return 线程池对象 */ public static ThreadPoolExecutor getThreadPool() { if (threadPool != null) { return threadPool; } else { synchronized (ThreadPoolUtil.class) { if (threadPool == null) { threadPool = new ThreadPoolExecutor(8, 16, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(64), new ThreadPoolExecutor.CallerRunsPolicy()); } return threadPool; } } } }
这篇关于开发Tips的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南