痛点1
query接口有时候需要传入多个参数,是不是意味着query就一定要在传参增加很多个呢?
不是,你只需传入对象
痛点1解决方案
1 定义对象
java
package com.wz.nls.business.req;
import lombok.Data;
@Data
public class DemoQueryReq {
private String mobile;
}
2 修改接口
java
public List<Demo> query(DemoQueryReq req) {
String mobile = req.getMobile();
DemoExample example = new DemoExample();
example.setOrderByClause("id desc");
DemoExample.Criteria criteria = example.createCriteria();
if (mobile != null) {
criteria.andMobileNameEqualTo(mobile);
}
return demoMapper.selectByExample(example);
}
3 测试
java
GET http://localhost:18000/nls/query?mobile=Huawei
Accept: application/json
依然可以查到结果。
痛点2
返回的结果,类型五花八门,也不好统一维护
痛点2解决方案
在/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/resp/CommonResp.java下
java
package com.wz.nls.business.resp;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class CommonResp<T> {
/**
* 业务成功或失败
*/
private boolean success=true;
/**
* 返回信息
*/
private String message;
/**
* 返回泛型数据
*/
private T cotent;
public CommonResp(T cotent) {
this.cotent = cotent;
}
}
注意这里是使用泛型,而不是object
- 泛型解决了 Object 的核心痛点 :编译期类型安全校验,杜绝
ClassCastException运行时异常; - 泛型让代码更简洁:无需手动强制类型转换,减少冗余代码;
- 泛型让代码更易读:类型语义清晰,团队协作更高效;
- 泛型不丢失复用性:和 Object 一样适配任意类型,同时兼顾安全。
那么现在,接口查询获得的结果就要用它来包装
java
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
或者,更简单的
java
@GetMapping("/query")
public CommonResp<List<Demo>> query(DemoQueryReq req) {
return new CommonResp<>(demoService.query(req));
}
测试看看,现在很接近前端获取的数据了

痛点3
现在query查到的实体就是表结构,这样其实不太安全,也不具备拓展性,我们有时候需要增减属性
痛点3解决方案
首先在pom中引入依赖,最外层父pom,添加
java
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
然后在business的子pom,添加
java
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
然后更新maven
然后在/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/resp/DemoQueryResp.java中引入
java
package com.wz.nls.business.resp;
import lombok.Data;
@Data
public class DemoQueryResp {
private Long id;
private String mobileName;
}
这里可以直接屏蔽掉password
同步需改接口的类型,这里只有引入了hutool才能用上BeanUtil.copyToList
java
public List<DemoQueryResp> query(DemoQueryReq req) {
String mobile = req.getMobile();
DemoExample example = new DemoExample();
example.setOrderByClause("id desc");
DemoExample.Criteria criteria = example.createCriteria();
if (mobile != null) {
criteria.andMobileNameEqualTo(mobile);
}
return BeanUtil.copyToList(demoMapper.selectByExample(example), DemoQueryResp.class);
}
}
java
@RestController
public class TestController {
@Resource
private DemoService demoService;
@GetMapping("/count")
public CommonResp<Long> count() {
return new CommonResp<>(demoService.count());
}
@GetMapping("/query")
public CommonResp<List<DemoQueryResp>> query(DemoQueryReq req) {
return new CommonResp<>(demoService.query(req));
}
}
痛点4
异常太多如何管理
痛点4解决方案
增加统一异常处理
在/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/controller/ControllerExceptionHandler.java下
java
package com.wz.nls.business.controller;
import com.wz.nls.business.resp.CommonResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一异常处理、数据预处理等
*/
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
/**
* 所有异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public CommonResp<Object> exceptionHandler(Exception e) {
CommonResp<Object> commonResp = new CommonResp<>();
log.error("系统异常:", e);
commonResp.setSuccess(false);
commonResp.setMessage("系统出现异常,请联系管理员");
return commonResp;
}
}
它相当于一个拦截器,所有的异常都会统一在这里收束。
但是这里有个缺点,所有的异常都是统一的回复,即便我们在函数中抛出异常
java
public List<DemoQueryResp> query(DemoQueryReq req) {
String mobile = req.getMobile();
DemoExample example = new DemoExample();
example.setOrderByClause("id desc");
DemoExample.Criteria criteria = example.createCriteria();
// if (mobile != null) {
// criteria.andMobileNameEqualTo(mobile);
// }
if (StringUtils.isBlank(mobile)) {
throw new RuntimeException("手机不能为空");
}
criteria.andMobileNameEqualTo(mobile);
return BeanUtil.copyToList(demoMapper.selectByExample(example), DemoQueryResp.class);
}
也无济于事,前端还是

而后端可以看到

这时候,我们可以针对性的根据异常来输出文本,在/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/controller/ControllerExceptionHandler.java下
java
package com.wz.nls.business.controller;
import com.wz.nls.business.resp.CommonResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一异常处理、数据预处理等
*/
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
/**
* 所有异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public CommonResp<Object> exceptionHandler(Exception e) {
CommonResp<Object> commonResp = new CommonResp<>();
log.error("系统异常:", e);
commonResp.setSuccess(false);
commonResp.setMessage("系统出现异常,请联系管理员");
return commonResp;
}
/**
* RuntimeException异常处理
* @param e
* @return
*/
@ExceptionHandler(value = RuntimeException.class)
@ResponseBody
public CommonResp<Object> exceptionHandler(RuntimeException e) {
CommonResp<Object> commonResp = new CommonResp<>();
log.error("系统异常:", e);
commonResp.setSuccess(false);
commonResp.setMessage(e.getMessage());
return commonResp;
}
}
通过RuntimeException的handler捕获异常,通过e.getMessage()来获取异常文本信息,并在最上层的接口抛出。
但是以上并不是最优解,以为异常太多了,我们最好自定义一个异常类,并且通过枚举来管理异常的细分种类
首先在/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/exception/BusinessExceptionEnum.java中
java
package com.wz.nls.business.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
public enum BusinessExceptionEnum {
DEMO_MOBILE_NOT_NULL("手机号不能为空!");
@Getter
private String desc;
}
然后在自定义类中使用它
java
package com.wz.nls.business.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class BusinessException extends RuntimeException {
private BusinessExceptionEnum e;
}
在拦截器/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/controller/ControllerExceptionHandler.java中这样定义
java
/**
* BusinessException异常处理
* @param e
* @return
*/
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public CommonResp<Object> exceptionHandler(BusinessException e) {
CommonResp<Object> commonResp = new CommonResp<>();
log.error("系统异常:", e);
commonResp.setSuccess(false);
commonResp.setMessage(e.getE().getDesc());
return commonResp;
}
使用时,我们直接抛出枚举类的desc
java
public List<DemoQueryResp> query(DemoQueryReq req) {
String mobile = req.getMobile();
DemoExample example = new DemoExample();
example.setOrderByClause("id desc");
DemoExample.Criteria criteria = example.createCriteria();
// if (mobile != null) {
// criteria.andMobileNameEqualTo(mobile);
// }
if (StringUtils.isBlank(mobile)) {
throw new BusinessException(BusinessExceptionEnum.DEMO_MOBILE_NOT_NULL);
}
criteria.andMobileNameEqualTo(mobile);
return BeanUtil.copyToList(demoMapper.selectByExample(example), DemoQueryResp.class);
}
痛点5
后台运维,看堆栈报错太复杂,如何简约化?

痛点5解决方案
/data/wz/JavaProject/im-nls/business/src/main/java/com/wz/nls/business/exception/BusinessException.java
重写fillInStackTrace方法防止递归,并且重写构造函数,原本使用父类可以传值进去,然后抛出异常的,
java
throw new RuntimeException("手机不能为空");
现在在构造函数使用super,然后狸猫换太子~
java
package com.wz.nls.business.exception;
import lombok.Data;
@Data
public class BusinessException extends RuntimeException {
private BusinessExceptionEnum e;
public BusinessException(BusinessExceptionEnum e) {
super(e.getDesc());
this.e = e;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
此时不显示null了,而是正常的错误信息文本
