需要掌握的技術知識點
目录:
lambda表达式
表单校验
单元测试的书写
抽象复用性强的代码
配置自动装载
AOP进行页面登录验证
数据类型序列化
JSON与对象的转换
控制器异常处理
lambda表达式
样例:
List<CartDTO> cartDTOList = orderDTO.getOrderDetailList()
.stream().map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
.collect(Collectors.toList());
使用场景
> 需要对两个不同的数据类(List)进行转换。
> 比如这个例子,需要将OrderDetailList 转成 CartDTOList
> 更多的用法,可以参考这篇博客: public ResultVO<Map<String, String>> create(@Valid OrderForm orderForm, BindingResult bindingResult) {} package com.product.sell.sell.form; import lombok.Data; import org.hibernate.validator.constraints.NotEmpty; @Data public class OrderForm { @NotEmpty(message="姓名必填") private String name; @NotEmpty(message = "手机号必填") private String phone; @NotEmpty(message = "地址必填") private String address; @NotEmpty(message = "openid必填") private String openid; @NotEmpty(message = "购物车不能为空") private String items; } 一般需要对参数进行验证的,都是保存的post接口 由于数据量比较大,直接定义一个对象来对传递的表单进行存储。 然后在FORM类里,通过注解的形式进行校验。 控制器层通过 if (bindingResult.hasErrors()) { log.error("【创建订单】参数不正确:orderForm={}", orderForm); throw new SellException(ResultEnum.PARAM_ERR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } 来获取到校验的结果 单元测试的书写 单元测试中需要加上这两个注解。 @RunWith(SpringRunner.class) @SpringBootTest public class OrderServiceImplTest {} 具体的单元测试: @Test public void findOne() { String orderId = "154494950704674973"; OrderDTO result = orderService.findOne(orderId); log.info("查询单个订单", result); Assert.assertNotNull(result); } 抽象复用性强的代码逻辑 场景:需要通过一个status值,获取到对应的中文解析。(1-》激活 0-》冻结) 这种一般用在后台,需要对数字进行解析。常规做法就是写 if 判断一下。 但是会存在非常多的重复性代码。 比较优秀的做法是,通过两个参数,直接获取到相对应的中文描述。 两个参数分别是 Integer status, Class<T> enumClass public class EnumUtil { // T 这里有可能是任何一种类型的枚举类 // T extends codeenum 这个接口 保证了他一定实现了接口里的方法 // 这就是写 CodeEnum,并让你的枚举类实现它的原因所在 public static <T extends CodeEnum> T getByCode(Integer code, Class<T> enumClass) { for (T each : enumClass.getEnumConstants()) { if (code.equals(each.getCode())) { return each; } } return null; } } 这里Class 为啥要加一个 T呢?具体的解释,可以参考这篇博客: https://www.cnblogs.com/zhima-hu/p/7352555.html 通俗的讲,就是指任何一个类。 但是代码里用到了一个方法: each.getCode() 如何保证传入的类一定有这个方法呢? <T extends CodeEnum> public interface CodeEnum { // 因为本次项目中code全部都是 Integer // 如果项目比较大,可以定义为 泛型 Integer getCode(); } 这样就保证了作为参数传入的类,必定实现了 getCode 这个方法,因此可以放心的使用。 然后我们在具体的数据类中,写一个方法: @Data //@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) // 上面这个废弃了。 // 如果结果中有null,则不去掉这个属性 // 还可以在yml里做全局配置.jackson --- //@JsonInclude(JsonInclude.Include.NON_NULL) public class OrderDTO { ... @JsonIgnore public OrderStatus getOrderStatusEnum() { return EnumUtil.getByCode(orderStatus, OrderStatus.class); } @JsonIgnore public PayStatus getPayStatusEnum() { return EnumUtil.getByCode(payStatus, PayStatus.class); } } lombok插件 引入依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> 即可使用注解的方式,免去getter setter的代码噩梦 记得要需要给 Idea 安装一个插件 配置自动装载 这次涉及到微信的开发,里面有些Jar包需要进行初始化配置(appID,secretID等) 这些配置内容,不写在控制器层,也不写在service层。而是直接将其装配成 bean。 @Component public class WechatPayConfig { @Autowired private WechatAccountPayConfig wechatAccountPayConfig; @Bean public BestPayServiceImpl bestPayService() { BestPayServiceImpl bestPayService = new BestPayServiceImpl(); bestPayService.setWxPayH5Config(wxPayH5Config()); return bestPayService; } @Bean public WxPayH5Config wxPayH5Config() { WxPayH5Config wxPayH5Config = new WxPayH5Config(); wxPayH5Config.setAppId(wechatAccountPayConfig.getMpAppId()); wxPayH5Config.setAppSecret(wechatAccountPayConfig.getMpAppSecret()); wxPayH5Config.setKeyPath(wechatAccountPayConfig.getKeyPath()); wxPayH5Config.setMchId(wechatAccountPayConfig.getMchId()); wxPayH5Config.setMchKey(wechatAccountPayConfig.getMchKey()); wxPayH5Config.setNotifyUrl(wechatAccountPayConfig.getNotifyUrl()); return wxPayH5Config; } } @Data @Component @ConfigurationProperties(prefix = "wechatpay") public class WechatAccountPayConfig { private String mpAppId; private String mpAppSecret; // 微信商户的一些配置信息 private String mchId; private String mchKey; private String keyPath; private String notifyUrl; } AOP进行页面登录验证 跟Laravel的middleware很类似。 通过一个pointcut,来定义需要进行切面验证的接口进行定义 通过几个方法(doBefore 和 doAfter)来定义进入这个方法之前(之后)需要做的逻辑 这边逻辑还有点不对。 登录这块儿的代码,需要重新写下。 public class HttpAspact { private final static Logger logger = LoggerFactory.getLogger(HttpAspact.class); @Pointcut("execution(public * com.product.sell.sell.controller.BuyerOrderController.list(..))") public void log(){} @Before("log()") public void doBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // url logger.info("url={}", request.getRequestURL()); // method logger.info("method={}", request.getMethod()); // IP logger.info("ip={}", request.getRemoteAddr()); // class 方法 logger.info("class method = {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); // 参数 logger.info("args={}", joinPoint.getArgs()); } @After("log()") public void doAfter() { } 数据类型序列化 6-12 一般像ctime,mtime这种类型的字段,DAO里定义成 Date 类型的。 但是可能前端需要的格式不是这个类型,而是一个String类型的时间戳,如何进行转换呢? @JsonSerialize(using = DateToLongSerializer.class) private Date updateTime; 这里用到了 JsonSerialize 注解。 public class DateToLongSerializer extends JsonSerializer<Date> { @Override public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeNumber(date.getTime() / 1000); } } JSON与对象的转换 6-11 代码里定义了一个 List 的值,但是前端表单传过来的是一个json字符串。 需要对这个字符串进行转换 public static OrderDTO convert(OrderForm orderForm) { Gson gson = new Gson(); OrderDTO orderDTO = new OrderDTO(); List<OrderDetail> orderDetailList = new ArrayList<>(); try { orderDetailList = gson.fromJson(orderForm.getItems(), new TypeToken<List<OrderDetail>>(){}.getType()); } catch (Exception e) { log.error("【对象转化出错】,string={}", orderForm.getItems()); throw new SellException(ResultEnum.PARAM_ERR); } orderDTO.setOrderDetailList(orderDetailList); return orderDTO; } 控制器异常处理 在程序抛出异常时,接口不能返回500错误,而是要返回异常信息。格式不能乱 @ControllerAdvice public class ExceptionHandle { @ExceptionHandler(value = SellException.class) @ResponseBody public ResultVO handle(Exception e) { if (e instanceof SellException) { SellException sellException = (SellException) e; return ResultVOUtil.error(sellException.getCode(), sellException.getMessage()); } return ResultVOUtil.error(-1, e.getMessage()); } }
共同學習,寫下你的評論
評論加載中...
作者其他優(yōu)質文章