写业务 / 各层的分工及注意事项 / 各实体类 / 数据库设计 参数校验

写业务 / 各层的分工及注意事项 / 各实体类 / 数据库设计 参数校验

实体类:

pojo 包下的类是对应数据库表的类vo 包下的类是后端封装数据返回给前端的类,便于展示数据,一般与pojo类不一样dos 包下的类是用来封装sql语句从数据库查出的数据 \ 有时也会在 entity 包下 (下面用entity代表封装数据库表的实体类)params 包下的类可以用来封装前端发送给后端的数据to 分布式情况下,一个服务调用另一个服务,会把数据封装到这个类里面

封装一个Result类来返回数据给前端比较好

@Data
@AllArgsConstructor
public class Result {
    private boolean success;

    private int code;

    private String msg;

    private Object data;

    public static Result success(Object data){
        return new Result(true,200,"success",data);
    }


    public static Result fail(int code,String msg){
        return new Result(false,code,msg,null);
    }
}

实体类的属性,使用包装类!!!

原始类型会 赋值 为0

包装类型会 赋值 为null

用于封装数据库表 的实体类,用原始类型可能会导致 更新出错!

实体类,默认实现序列化接口!!!

implements Serializable
private static final long serialVersionUID = 1L;    //序列化ID 便于反序列化

Entity注解:(使用Mybatis-plus)

@TableName(“pms_attr_attrgroup_relation”)

将指定的数据库表和 JavaBean 进行映射

@TableId

如果表的id名字 和 类的id名字不同,要用此注解【不管怎么样,加上就行】

@TableField:

非主键字段,value映射表字段名:
    @TableField(value = "sort")
    private Integer attrSort;

类中属性不存在表中:
    @TableField(exist = false)
    private Integer attrSort;

Entity的创建时间和更新时间可以自动填充

@TableField(fill = FieldFill.INSERT_UPDATE)

private Date createTime;

实体类注解:(lombok,使得实体类不用写各种方法)

lombok使用参考网址:https://www.jianshu.com/p/2543c71a8e45

1、idea装插件

2、导入依赖

3、在实体类上标明注解,常用@Data

实体类参数校验(比如不能为空或者要符合什么要求)在最后面

写业务,

一定要先明确接口的 路径 参数 以及 后端返回的值

通过路径,判断对应的是哪张表,判断是在哪个controller写业务,判断对应的是哪个entity(封装数据库表的实体类)

然后用 vo 封装 后端和前端 互相传递的参数

controller 处理请求,接受和校验数据

Service 接受controller传来的数据,进行业务处理。

​ 1、涉及到哪些表,就注入哪些表的service

​ 2、往往就是vo和entity的转换,然后再进行操作。

​ 同名的属性,先用BeanUtils.copyProperties(源对象,目标对象)

​ 不同名的属性,再一个个赋值上去

​ 3、如果是单表操作,看看Iservice有没有直接可以用的。

​ 如果是BaseMapper里面有直接可以用的,而且这张表不是属于自己处理的。先在其他service1里面封装函数再调用

Controller 接受Service处理完的数据,封装页面指定的vo

Controller层注意事项:

1、不要用 map接收前端传过来的值,因为别人不知道里面有什么参数

最好还是写一个实体类进行封装

Service层注意事项:

1、 赋值到entity时,不用给实体类的id赋值,它会在数据库中自动生成

2、 当实体类保存过数据库之后(之前没赋id值),可以直接get实体类的id!!!

3、Service层最好还是注入service层,不要用其他service的dao

service层使用baseMapper , Iservice

​ this.(Iservice里面的方法)

    • service接口要 extends IService<封装数据库表的对象>
    • service接口的实习类 要 extends ServiceImpl<Mapper接口, 封装数据库表的对象> implements LoginService

​ this.baseMapper.(baseMapper里面的方法)

    • Dao层的Mapper接口要 extends BaseMapper<Tb_User>

QueryWrapper<>写法:

  • QueryWrapper queryWrapper = new QueryWrapper<>();
  • ​ //如果传过来的数据不是空的,就进行多参数查询
  • ​ if (!StringUtils.isEmpty(key)) {
  • ​ queryWrapper.eq(“brand_id”,key).or().like(“name”,key);
  • ​ }
  • 或者
  • this.getOne (new QueryWrapper<Tb_User> ().eq (“mobile”,userLoginVo.getMobile ()));

Dao层注意事项:

1、业务量很大的时候,不应该使用联表查询,两种表的笛卡儿积数据量太大会有危险

数据库设计注意事项:

分布式 数据库表的设计会有冗余,以便分库分表。以及减少联表查询。【多表查询是笛卡儿积】

但是这样也会导致修改表中某一字段时,也要修改其他表字段的问题【不过查询比修改的数量多很多,所以冗余是值得的】

后端字段校验功能:(包含错误枚举 和 处理异常 知识点)

1.简单使用JSR303

1.0 导入依赖

springboot 2.3.2之后使用的版本:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.3.7.RELEASE</version>
</dependency>


springboot 2.3.2以前使用的版本:
<dependency>
     <groupId>javax.validation</groupId>
     <artifactId>validation-api</artifactId>
     <version>2.0.1.Final</version>
</dependency>

1.1 给Bean添加校验注解

如:@NotNull
【上网搜一下能配哪些注解】
【其他能配的:比如@URL / @Pattern(),里面写正则表达式,注意两边要去掉斜杠】

注解里有默认的message,如果想修改,可以这样写:@NotNull(message = "id不能为空")

1.2 给方法的参数添加上 @Valid 注解 。也可以直接在方法获取错误信息进行处理

 @RequestMapping("/save")
  public R save(@Valid @RequestBody BrandEntity brand){     // @Valid 放在 @RequestBody前面
      brandService.save(brand);
      return R.ok();
  }

@PostMapping("/regist")
public String regist(@Valid UserRegistVo vo, BindingResult result, RedirectAttributes redirectAttributes){

    // 校验参数是否出错
    if(result.hasErrors()){
        Map<String, String> errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
        redirectAttributes.addFlashAttribute("model",errors);
        return "redirect:/reg.html";
    }

    // 注册

    return "redirect:/login.html";
}

1.3 定义异常枚举,方便后面的异常处理器调用

/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为5位数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
*  10: 通用
*      001:参数格式校验
*  11: 商品
*  12: 订单
*  13: 购物车
*  14: 物流
*/
public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VALID_EXCEPTION(10001,"参数格式校验失败");


    private int code;
    private String msg;
    BizCodeEnume(int code,String msg){
        this.code = code;
        this.msg = msg;
    }


    public int getCode() {
        return code;
    }


    public String getMsg() {
        return msg;
    }
}

1.4 定义异常处理器处理参数校验异常

/**
* 集中处理所有异常
*/
@Slf4j
@RestControllerAdvice(basePackages = "com.xxxx.gulimall.product.controller")
public class ExceptionControllerAdvice {


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handlerVaildException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());
        BindingResult bindResult = e.getBindingResult();

        Map<String,String> errorMap = new HashMap<>();
        bindResult.getFieldErrors().forEach((fieldError -> {
            errorMap.put(fieldError.getField(), fieldError.getField());
        }));
        return R.error(BizCodeEnume.VALID_EXCEPTION.getCode(),BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data",errorMap);
    }


    //不建议这样写,加上没有报错信息,坑
    // 若上面没有捕获,就会到这个方法。【处理所有异常】
    //@ExceptionHandler(value = Throwable.class)
    //public R handlerException(Exception e){
    //    e.printStackTrace();
    //    return R.error();
    //}
}

2.有多个情况时,使用分组校验(比如新增 和 修改的情况不同) ,与上面不同的地方:

2.1 与上面1.1不同,注解时需要加上分组,不加分组则默认失效【如果需要所有分组情况都校验,加上全部分组】

​ 定义分组:分组类型可以任意,但推荐新建一个空接口,然后在这里写上

定义分组:
    public interface AddGroup {}
    public interface UpdateGroup {}
Bean注解:
@NotNull(message = "修改必须指定id", groups = {UpdateGroup.class})    // 更新时需校验
@NotBlank(message = "品牌名不能为空", groups = {AddGroup.class,UpdateGroup.class})    // 所有情况需校验

2.2 与1.2不同,要给方法的参数添加上 @Validated( {分组} ) 注解

  @RequestMapping("/save")
  public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
      brandService.save(brand);
      return R.ok();
  }

3.使用自定义校验(就是新增一个自定义的校验注解)

3.1 编写一个自定义的校验注解

【message要关联一个文件,要新建这个文件。这样注解就有默认的message。当然在使用的时候也可以重新写message】

新建 ValidationMessages.properties :
    com.xxxx.common.valid.ListValue.message=只能在指定范围里取值
@Documented
@Constraint(validatedBy = { com.xxxx.common.valid.ListValueConstraintValidator.class })    // 校验器,需要自定义,可以多个
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.xxxx.common.valid.ListValue.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    int[] vals() default { };
}

3.2 编写一个自定义的校验器 (实例里的校验器作用是:值只能在 用注解时指定的值的范围内)

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> { //泛型:第一个是注解 第二个是校验的字段

    private Set<Integer> set = new HashSet<>();

    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    //判断是否校验成功
    /**
     * @param value 需要校验的值
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {

        return set.contains(value);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沛权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值