经过一段时间的学习,总结一下自己的想法,不一定正确。
一个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 提供特定的数据库产生主键, 该方式更有利于数据库的移植
主键在数据库中的表现:
Entity里,如果对字段进行限制,可以通过validation注解,参考文章:
SpringBoot使用Validation校验参数
VO
VO是用来配合Repository进行数据库操作的类,一般用来分页查询
在BaseRepository的源码里可以看到
可以在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是一些查询条件,
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;
});
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));
}