一.Java 实体映射工具 MapStruct
声明:
1、DO(业务实体对象),DTO(数据传输对象)。
2、我的代码中用到了 Lombok ,不了解的可以自行了解一下,了解的忽略这条就好。
在一个成熟的工程中,尤其是现在的分布式系统中,应用与应用之间,还有单独的应用细分模块之后,DO 一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。
这种 对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦。
MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址: http://mapstruct.org/
1.pom文件依赖
<!--实体类与Model类转换的利器-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.3.0.Final</version>
</dependency>
2.定义vo实体与dto传输对象
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
private Long id;
private String name;
private String email;
private Date birthday;
private User user;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private Integer age;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class PersonDTO {
private Long id;
private String name;
/**
* 对应 Person.user.age
*/
private Integer age;
private String email;
/**
* 与 DO 里面的字段名称(birthDay)不一致
*/
private Date birth;
/**
* 对 DO 里面的字段(birthDay)进行拓展,dateFormat 的形式
*/
private String birthDateFormat;
/**
* 对 DO 里面的字段(birthDay)进行拓展,expression 的形式
*/
private String birthExpressionFormat;
}
3. Mapper 接口
package com.zsc.shixun.model.article;
import com.zsc.shixun.entity.Article;
import org.mapstruct.Mapper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author ZWYZY
* @since 2020/6/18
*/
@Service
@Mapper(componentModel = "spring")
public interface ArticleMapping {
/**
* @param article
* @return
*/
ArticleVO entityToVo(Article article);
/**要实现列表转换必须先实现上面的映射
* entity to vo
*
* @param articleList
* @return
*/
List<ArticleVO> entitysToVos(List<Article> articleList);
}
4. 编译MapStruct之后,手工编译
<!--实体转vo必要的配置-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</path>
<path>
<!--实体与dto使用了lombok插件,必须添加这个-->
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
会自动在 target/classes 下生成对应的实现类
5.注解关键词
@Mapper //只有在接口加上这个注解, MapStruct 才会去实现该接口
@Mapper //里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个
default://默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象
spring://在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入
@Mapping://属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性
source://源属性
target://目标属性
dateFormat://String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat 的日期格式
ignore: //忽略这个字段
@Mappings://配置多个@Mapping
@MappingTarget //用于更新已有对象
@InheritConfiguration //用于继承配置
二.后端验证
1.pom文件依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.实体类添加校验
package demo.rest;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* description:
* author: yangzihe
* date: 2019-05-16 15:50
**/
@Data
public class User {
@NotNull(message = "用户名不可为空")
private String name;
@NotNull(message = "密码不可为空")
private String password;
}
3.控制层添加校验
@RestController
public class DemoController {
@GetMapping("valid")
public String test1(@Validated User user, BindingResult result) {//@Valid注解也可
System.out.println(user);
System.out.println("result=" + result);
if (result.hasErrors()) {
StringBuilder sb = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
sb.append(error.getDefaultMessage() + ";");
}
System.out.println(sb.toString());
return sb.toString();
}
return "success";
}
}
注意:如果要校验的不是java bean 要在控制器添加@Validated 而不是在参数旁加,否则会失效
参考资料: 1.嵌套验证:https://blog.csdn.net/weixin_33853794/article/details/85992438
2.常用注解: https://blog.csdn.net/weixin_34234829/article/details/93407285
三.全局异常处理及返回值封装
1.返回值封装
package com.zsc.shixun.common;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
/**
* <p>
* 返回值封装类
* </p>
*
* @author Administrator
*/
@Component
@NoArgsConstructor
public class CommonResult<T> {
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public Object getData() {
return data;
}
public CommonResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
private Integer code;
public void setCode(Integer code) {
this.code = code;
}
public void setMsg(String msg) {
this.msg = msg;
}
public void setData(T data) {
this.data = data;
}
private String msg;
private T data;
public CommonResult(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public CommonResult(ResultCode code) {
this.code = code.getCode();
this.msg = code.getMsg();
}
}
2.返回值异常状态码
package com.zsc.shixun.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>
* 响应码及描述常量
* </p>
*
* @author ZWYZY
* @since 2020/4/21
*/
@Getter
@AllArgsConstructor
public enum ResultCode {
//ctrl+shift+u ,小写变大写
LIKE_CLICK_FAIL(900001,"点赞失败"),
COMMENT_DELETE_FAIL(800005,"不好意思,删除评论失败哦,亲"),
USER_DELETE_YOURSELF_FAIL(700004,"不好意思,你自己不能删除自己哦,亲"),
USER_MANAGE_INSERT_FAIL(700003,"不好意思,管理员创建失败哦,亲"),
USER_MANAGE_DELETE_FAIL(700002,"不好意思,用户删除失败哦,亲"),
USER_MANAGE_UPDATE_FAIL(700001,"不好意思,用户更改失败哦,亲"),
COLLECT_HAS_EXIST(600004,"不好意思,已有该收藏夹类型哦,亲"),
COLLECT_INSERT_FAIL(600003,"不好意思,收藏夹创建失败哦,亲"),
COLLECT_DELETE_FAIL(600002,"不好意思,收藏夹删除失败哦,亲"),
COLLECT_UPDATE_FAIL(600001,"不好意思,收藏夹更改失败哦,亲"),
TYPE_HAS_EXIST(500004,"不好意思,已有该文章类型了哦,亲"),
TYPE_INSERT_FAIL(500003,"不好意思,类型创建失败哦,亲"),
TYPE_DELETE_FAIL(500002,"不好意思,类型删除失败哦,亲"),
TYPE_UPDATE_FAIL(500001,"不好意思,类型更改失败哦,亲"),
ARTICLE_INSERT_FAIL(400003,"不好意思,创建文章失败哦,亲"),
ARTICLE_DELETE_FAIL(400002,"不好意思,文章删除失败哦,亲"),
ARTICLE_UPDATE_FAIL(400001,"不好意思,文章修改失败哦,亲"),
NOTICE_DELETE_FAIL(300003,"不好意思,公告删除失败哦,亲"),
NOTICE_INSERT_FAIL(300002,"不好意思,公告插入失败哦,亲"),
NOTICE_UPDATE_FAIL(300001,"不好意思,公告更改失败,亲"),
USER_UPDATE_FAIL(200002,"本次操作未能成功,亲!"),
FILE_UPLOAD_ERROR(200001,"文件上传失败"),
AUTHORITY_HAS_EXIST(403,"亲,当前操作没有权限哦!"),
USERNAME_HAS_EXIST(100002,"用户名太受欢迎了,请换一个吧,亲"),
USER_HAS_EXIST(100001,"邮箱已注册"),
EXCEL_NOT_DATA(-7,"当前没数据"),
USER_NOT_FOUND(10000, "用户不存在"),
ERROR(-1, "未知错误"),
SUCCESS(200, "响应成功"),
CHANGE(1, "改变成功"),
CHANGE_NOT(0, "改变失败"),
EMAIL_NOT_FOUND(10000,"该邮箱还没注册"),
DATA_ERROR(-2, "输入数据错误"),
USER_PASSWORD_NOT_FOUND(4001001, "用户名密码不匹配"),
USER_BAN(4001002, "该用户已经被禁用请联系管理员"),
CODE_NULL(4001003, "验证码失效请重新获取"),
CODE_ERROR(4001004, "请输入正确的验证码"),
USERNAME_HAS(4001005, "该账号已被占用"),
REGIST_ERROR(4001006, "注册失败"),
PHONE_NOT_TRUE(4001007, "手机号格式错误"),
SEND_MAX(4001008, "当日发送已上限"),
USER_HAS_LOGIN(4001009,"用户已经登录无需再登录"),
DATABASE_DEPENDENT_ERROR(-3, "数据库数据之间依赖错误"),
File_ERROR(-4, "上传的文件错误"),
EXCELDATA_ERROR(-5, "文件内容错误,操作全部取消"),
DATA_NULL(-6, "查询的信息为空");
private Integer code;
private String msg;
}
3.返回值异常工具类
package com.zsc.shixun.common;
/**
* <p>
* 返回值封装工具类
* </p>
*
* @author ZWYZY
* @since 2020/4/21
*/
public class ResultUtil {
public static<T> CommonResult<T> success(T t) {
CommonResult<T> result = new CommonResult<>();
result.setCode(ResultCode.SUCCESS.getCode());
result.setMsg(ResultCode.SUCCESS.getMsg());
result.setData(t);
return result;
}
public static CommonResult success() {
return success(null);
}
public static<T> CommonResult<T> error(Integer code, String msg) {
CommonResult<T> result = new CommonResult<>();
result.setCode(code);
result.setMsg(msg);
result.setData(null);
return result;
}
public static<T> CommonResult<Object> error(Integer code, String msg, String data) {
CommonResult<Object> result = new CommonResult<>();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
public static<T> CommonResult<T> error(ResultCode resultCode) {
CommonResult<T> result = new CommonResult<>();
result.setCode(resultCode.getCode());
result.setMsg(resultCode.getMsg());
result.setData(null);
return result;
}
}
4.全局异常捕获处理
package com.zsc.shixun.exception;
import com.zsc.shixun.common.CommonResult;
import com.zsc.shixun.common.ResultUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
/**
* @author winner
* @description: ZWYZY 定义的全局异常处理
* @date 2020/4/14
*/
@Configuration
@RestControllerAdvice
public class ErrorExceptionHandler<T> {
/**ApiException为自定义运行时异常类子类
* api异常处理返回json封装字符串对象
*
* @param e
* @return
*/
@ExceptionHandler(value = ApiException.class)
public CommonResult<Object> paramError(ApiException e) {
return ResultUtil.error(e.getCode(), e.getMessage(), e.getData());
}
/**
* 校验异常处理
*
* @param e
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public CommonResult bindExceptionHandler(BindException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
return ResultUtil.error(400, message);
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
public CommonResult methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException e) {
// String message = e.getLocalizedMessage().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return ResultUtil.error(400, "数据验证错误");
}
/**
* 校验异常处理
*
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public CommonResult constraintViolationExceptionHandler(ConstraintViolationException e) {
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
return ResultUtil.error(400, message);
}
/**
* 校验异常处理
*
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public CommonResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return ResultUtil.error(400, message);
}
}