经过一段时间的学习,总结一下自己的想法,不一定正确。
一个spring boot模块,一般由Controller,Service,Repository,Entity,VO组成。现在将项目中常用的写法总结一下

Entity

Entity一般对应数据库,常用写法是:

@Entity
@Table(name = "tb_vaccine")
@JsonIgnoreProperties(ignoreUnknown = true)
public class VaccinesEntity extends BaseEntity {

    @Id
    @TableGenerator(name = "ClassVaccine_gen",
            table = "t_com_id_generator_r",// 表名
            pkColumnName = "seq_name",  // 列1,varchar 类型,存储生成ID的键
            pkColumnValue = "ClassVaccine_id",//列2,int 类型,存储ID值
            valueColumnName = "seq_value", // 列1的键值
            allocationSize =50// 增长值
    )
    @GeneratedValue(strategy = GenerationType.TABLE,
            generator = "ClassVaccine_gen")
    private Long id;


    /**
     * 名称
     */
    @Column(name = "vaccine_name", length = 50)
    private String  vaccineName;

   /**
     * 禁用,启用
     */
    @Column(name = "logicDel")
    private Boolean logicDel;
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getVaccineName() {
        return vaccineName;
    }

    public void setVaccineName(String vaccineName) {
        this.vaccineName = vaccineName;
    }

    @Override
    public Boolean getLogicDel() {
        return logicDel;
    }

    @Override
    public void setLogicDel(Boolean logicDel) {
        this.logicDel = logicDel;
    }
}

其中,@Column对应的是数据库的字段名,@TableGenerator是表生成器,将当前主键的值单独保存到数据库的一张表里去,主键的值每次都是从该表中查询获得。

@GeneratedValue注解主要就是为一个实体生成一个唯一标识的主键,提供了主键的生成策略,有两个属性,分别是strategy和generator

generator属性的值是一个字符串,默认为"",其声明了主键生成器的名称

(对应于同名的主键生成器@SequenceGenerator和@TableGenerator)。

strategy属性:

-AUTO主键由程序控制, 是默认选项 ,不设置就是这个
-IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式
-SEQUENCE 通过数据库的序列产生主键, MYSQL 不支持
-Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植

主键在数据库中的表现:

springboot实体类的原则 springboot的entity_主键


Entity里,如果对字段进行限制,可以通过validation注解,参考文章:

SpringBoot使用Validation校验参数

Spring Boot中的数据校验 Validation

VO

VO是用来配合Repository进行数据库操作的类,一般用来分页查询

在BaseRepository的源码里可以看到

springboot实体类的原则 springboot的entity_数据库_02


可以在VO里定义一些查询条件

public class VaccineVO extends BaseVO {

    @ApiModelProperty("名称")
    @QueryCriteria(expression = EXPRESSION.ALL_LIKE, name = "vaccineName")
    private String vaccineName;

    public String getVaccineName() {
        return vaccineName;
    }

    public void setVaccineName(String vaccineName) {
        this.vaccineName = vaccineName;
    }
    public Boolean getLogicDel() {
        return logicDel;
    }

    public void setLogicDel(Boolean logicDel) {
        this.logicDel = logicDel;
    }
}

这样就可以根据名称来进行查询了。这个@QueryCriteria里的name的值,要和Entity里对应,expression是一些查询条件,

springboot实体类的原则 springboot的entity_ci_03

Repository

Repository一般是对数据库的操作,集成BaseRepository,jpa已经封装了常用的数据库操作,如果有特殊需求,可以自己写

public interface IVaccineManageRepository extends BaseRepository<VaccinesEntity,Long, VaccineVO> {
}

对于一些特殊要求,可以通过jpa命名规则来操作,比如

Long countByCreateTimeBetweenAndLogicDelFalse(Long startTime, Long endTime);

这句话意思就是统计CreateTime在startTime和endTime,并且LogicDel这个字段是false的数据。这个按照规则命名的方法,省去了自己写sql语句的麻烦,参考规则:jpa命名规则 jpa使用sql语句 @Query 对于一些复杂的要求,需要自己写sql语句

@Query(nativeQuery = true ,value = "select Count(DISTINCT real_name)  from t_pre_view_record_m o where o.article_id=?1 and o.is_logic_del=0")
    Long countStudentPeople(Long articleId);

Service

service是用来封装对外的方法,里边写一些数据库操作的逻辑。一般的就是对数据库的增删改查

@Service
public class VaccineService {
    @Resource
    private IVaccineManageRepository repository;

    /**
     * 分页的列表
     */
    public Page<VaccinesEntity> list(Pageable page, VaccineVO vo) {

        return repository.findByCriteria(page, vo, null);
    }

    /**
     * 得到所有
     */
    public List<VaccinesEntity> getAll() {
        return repository.findAll();
    }

    /**
     * 添加
     */
    @Transactional
    public ResponseEntity addVaccine(VaccinesEntity entity) {
        return ResponseEntity.ok(repository.save(entity));
    }

    /**
     * 根据id查询对应信息
     */
    @Transactional
    public VaccinesEntity getVaccineById(Long id) {
        Optional<VaccinesEntity> opt = repository.findById(id);
        if (opt.isPresent()) {
            return opt.get();
        }
        return null;
    }

    /**
     * 禁用、启用
     */
    @Transactional
    public ComServiceResVo deleteVaccine(Long id, Boolean logicDel) {
        Optional<VaccinesEntity> opt = repository.findById(id);
        if (opt.get() == null) {
            return ComServiceResVo.badRequest("已不存在");
        } else {
            VaccinesEntity entity = opt.get();
            entity.setLogicDel(logicDel);
            return ComServiceResVo.ok(repository.save(entity));
        }
    }


    /**
     * 编辑 
     */
    public ComServiceResVo updateVaccine(Long id, VaccinesEntity entity) {
        Optional<VaccinesEntity> opt = repository.findById(id);
        if (opt.get() == null) {
            return ComServiceResVo.badRequest("已不存在");
        } else {
            VaccinesEntity course = opt.get();
            if (StringUtils.isNotBlank(entity.getVaccineName())) {
                course.setVaccineName(entity.getVaccineName());
            }
            course.setLogicDel(entity.getLogicDel());
            return ComServiceResVo.ok(repository.save(course));
        }
    }


}

对于分页,如果entity里边有其他entity,比如

/**
     * 目录关联
     */
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "cy_id", referencedColumnName = "id")
    private ArtCategoryEntity cy;

    /**
     * 分类关联
     */
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "classify_id", referencedColumnName = "id")
    private ArtClassifyEntity classify;

那就可以这样返回

return articleRepository.findByCriteria(pageable, vo, (root, query, criteriaBuilder) -> {
          
            //目录
            if (null != vo.getCyId()) {
                predicate.getExpressions().add(criteriaBuilder.equal(root.get("cy").get("id"), vo.getCyId()));
            }

            //分类
            if (null != vo.getClassifyId()) {
                predicate.getExpressions().add(criteriaBuilder.equal(root.get("classify").get("id"), vo.getClassifyId()));
            }

       
            return predicate;
        });

可以参考
JPA 中CriteriaQuery 查询

Controller

controller一般是提供前端用的接口,我这边碰到两种controller,一个是同一个工程里,使用js调用的接口,另一个controller是对外的,结合swagger
第一种controller

@Controller
@RequestMapping("vaccine/manage")
public class VaccineManageController {
    /**
     * js 路径
     */
    private static final String PREFIX_JSP_PATH = "back-end/vaccine/";

    @Resource
    private VaccineService service;
    /**
     * 首页
     */
    @GetMapping("/home")
    public String vaccine() {
        return PREFIX_JSP_PATH + "vaccine";
    }

    /**
     * 添加
     */
    @PostMapping("/add")
    @ResponseBody
    public ResponseEntity add(@Valid @ModelAttribute VaccinesEntity entity, BindingResult result) {
        if (result.hasErrors()) {
            return ResponseEntityFacade.facade(ComServiceResVo.badRequest("提交参数不完整"));
        } else {
        
            return service.addVaccine(entity);
        }
    }

	//列表
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ResponseBody
    public ComDatatableResVo findCondition(Pageable pageable, VaccineVO vo) {
        return new ComDatatableResVo(service.list(pageable, vo));
    }

    /**
     * 根据id查询对应信息
     */
    @GetMapping("/query/{id}")
    @ResponseBody
    public VaccinesEntity queryVaccineById(@PathVariable("id") Long id) {
        return service.getVaccineById(id);
    }


    /**
     * 禁用、启用
     */
    @PostMapping("/update/{id}/status")
    @ResponseBody
    public ResponseEntity updateStatus(@PathVariable("id") Long id,@RequestParam Boolean logicDel) {
        return ResponseEntity.ok(service.deleteVaccine(id,logicDel));
    }

    /**
     *编辑
     */
    @PostMapping("/update/{id}")
    @ResponseBody
    public ResponseEntity updateVaccine(@PathVariable("id") Long id,@Valid @ModelAttribute VaccinesEntity entity) {
        return ResponseEntity.ok(service.updateVaccine(id,entity));
    }

}

调用的方式是在js里边使用ajax
例如:

$.ajax({
                    type: "POST",
                    url: _CONTEXT_PATH + "vaccine/manage/add",
                    dataType: "json",
                    data: form.serialize(),
                    error: function (errorRes) {
                        swal({title: "oops !!", text: errorRes.responseText, type: "error",}, function () {
                        });
                    },
                    success: function (responseData) {
                        swal({title: "Good job!!", text: responseData.message, type: "success"}
                        ).then(function () {
                            $("#myModal").modal("hide");
                            $('#dataTable').dataTable().api().table().draw();
                        });
                    }
                });

另外一种controller是结合swagger使用
注解使用@RestController,不是@Controller,比如

@RestController
@RequestMapping("/mg/vue/label/")
@Api(tags = {"vue后台-文章"})
public class ArtlabelVueMgController {
....
 /**
     * 查询文章标签列表
     */
    @PostMapping(value = "labels")
    @ApiOperation(value = "查询文章标签列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", required = true, value = "第几页,从0开始,默认为第0页"),
            @ApiImplicitParam(name = "size", required = true, value = "每一页的大小,默认为10"),
            @ApiImplicitParam(name = "sort", required = true, value = "排序相关的信息,以`property[,ASC|DESC]`的方式组织,例如`sort=firstname&sort=lastname,desc`表示在按firstname正序排列基础上按lastname倒序排列。"),
            @ApiImplicitParam(name = "name", required = false, value = "name"),
            @ApiImplicitParam(name = "logicDel", required = false, value = "是否禁用"),
    })

    public ResponseEntity getCategorys(
            Pageable pageable,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) Boolean logicDel) {

        ArtLabelCVO vo = new ArtLabelCVO();
        if (!StringUtils.isEmpty(name)){
            vo.setName(name);
        }
        if (null!=logicDel) {
            vo.setLd(logicDel);
        }

        return ResponseEntity.ok(labelService.findByCondition(pageable, vo));
    }
 /**
     * 根据id查询文章标签详情
     */
    @PostMapping(value = "label/{id}")
    @ApiOperation(value = "根据id查询文章标签详情")
    public ResponseEntity getLabelById(
            @PathVariable("id") long id

    ) {
        ArtLabelEntity art = labelService.findById(id);
        if (null == art) {
            return ResponseEntity.badRequest().body("查询信息失败");
        }
        return ResponseEntity.ok(art);
    }


    /**
     * 新增
     */
    @PostMapping(value = "addLabel")
    @ApiOperation(value = "新增文章标签")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", required = true, value = "名称"),
            @ApiImplicitParam(name = "desc", required = true, value = "描述"),

    })
    public ResponseEntity create(@Valid @ModelAttribute ArtLabelEntity entity
            , BindingResult result) {
        if (result.hasErrors()) {
            log.debug("create errors={}",result.getAllErrors());
            return ResponseEntityFacade.facade(ComServiceResVo.badRequest(messageSource.getMessage("validation.complete", null, null)));
        }
        return ResponseEntity.ok(labelService.create(entity));
    }


    /**
     * 更新
     */
    @PostMapping(value = "updateLabel/{id}")
    @ApiOperation(value = "更新文章标签")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", required = true, value = "类别名称"),
            @ApiImplicitParam(name = "desc", required = true, value = "描述"),
    })
    public ResponseEntity update(@Valid @ModelAttribute ArtLabelEntity entity,
                                  @PathVariable("id") String id, BindingResult result) {
        if (result.hasErrors()) {
            log.debug("create errors={}",result.getAllErrors());
            return ResponseEntityFacade.facade(ComServiceResVo.badRequest(messageSource.getMessage("validation.complete", null, null)));
        }
        entity.setId(NumberUtils.parseNumber(id, Long.class));
        return ResponseEntity.ok(labelService.update(entity));

    }

    /**
     * 停用、启用
     */
    @PostMapping(value = "updateLabelIsEnable/{id}")
    @ApiOperation(value = "更新文章标签启用、禁用状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "state", required = true, value = "是否禁用"),
    })
    public ResponseEntity save(@PathVariable("id") Long id, @RequestParam boolean state) {
        ArtLabelEntity entity = labelService.findById(id);
        entity.setLogicDel(state);
        return ResponseEntity.ok(labelService.delete(entity));
    }
}

@ApiImplicitParam使用这个对参数进行说明,如果是url传入的参数,可以使用@PathVariable标记:比如

@PostMapping(value = "label/{id}")
    @ApiOperation(value = "根据id查询文章标签详情")
    public ResponseEntity getLabelById(
            @PathVariable("id") long id

    )

如果是新增或者修改这样的,可以传一个实体类,通过@Valid @ModelAttribute注解

@PostMapping(value = "addLabel")
    @ApiOperation(value = "新增文章标签")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", required = true, value = "名称"),
            @ApiImplicitParam(name = "desc", required = true, value = "描述"),

    })
    public ResponseEntity create(@Valid @ModelAttribute ArtLabelEntity entity
            , BindingResult result) {
        if (result.hasErrors()) {
            log.debug("create errors={}",result.getAllErrors());
            return ResponseEntityFacade.facade(ComServiceResVo.badRequest(messageSource.getMessage("validation.complete", null, null)));
        }
        return ResponseEntity.ok(labelService.create(entity));
    }

springboot(服务端接口)获取URL请求参数的几种方法