背景:
关于基类控制层的改造实践,网上其实有很多不同的通用controller层的模块,在实际开发过程,会遇到各种各样的问题,还是在Service层的通用改造案例。后台代码使用的若依Spring Boot、Spring Cloud & Alibaba架构搭建。内置了一些基础的核心功能模块。
在实际的开发过程中,开发人员编码习惯,思考方式各不相同,导致controller控制层常用的增删查改命名规则各不相同,增加前后端开发人员,交流和阅读难度。在此环境下,统一常用方法的命名规则和编码习惯,形成统一的代码风格。便于后续人员的开发和理解。
统一命名规则
-
方法命名:为了保证一致性,可以约定使用动词+名词的方式来进行方法命名,例如
addUser
,deleteUser
,updateUser
,getUserById
等。这样不仅可以让API更加直观易懂,同时也方便前端开发人员快速定位和调用接口。 -
参数传递:定义一套通用的请求参数规范,比如所有的查询条件都封装在一个名为
query
的对象中,更新操作的参数则使用updateInfo
这样的命名模式。 -
响应格式:统一响应的数据格式,例如返回一个包含状态码(status)、消息(message)以及数据(data)的JSON对象。这有助于减少前端解析数据的工作量,并且在出现错误时能够快速定位问题。
编码习惯
-
注释规范:确保每个控制器方法都有适当的注释说明其功能、输入输出参数以及可能抛出的异常。这有助于新加入团队的成员更快地理解业务逻辑。
-
异常处理:为所有可能产生异常的操作提供统一的异常处理机制。可以在基类控制器中实现全局异常处理器,捕获并统一格式化异常信息。
-
分层设计:坚持分层架构原则,确保Controller层只负责接收请求和返回响应,具体的业务逻辑应该交给Service层来处理。这样可以保持控制器的简洁性,并且易于测试。
团队沟通
-
定期组织代码审查会议,鼓励团队成员分享最佳实践,讨论存在的问题并提出改进措施。
-
创建文档或Wiki页面记录编码规范,让每位开发者都能随时查阅。
技术体系:
基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构。
后端采用Spring Boot、Spring Cloud & Alibaba。
问题现象:
第一步:创建一个web层通用数据处理controller-BaseController
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sunward.common.i18n.utils.I18nUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import javax.servlet.http.HttpServletRequest;
/**
* web层通用数据处理
*
* @author sunward
*/
public class BaseController
{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(DateUtils.parseDate(text));
}
});
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(IPage<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setRows(list.getRecords());
rspData.setMsg(I18nUtil.getMessage("query.success"));
rspData.setTotal(list.getTotal());
return rspData;
}
/**
* 返回成功
*/
public AjaxResult success()
{
return AjaxResult.success();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
return AjaxResult.success(message);
}
/**
* 返回成功消息
*/
public AjaxResult success(Object data)
{
return AjaxResult.success(data);
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
return AjaxResult.error();
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
return AjaxResult.error(message);
}
/**
* 返回警告消息
*/
public AjaxResult warn(String message)
{
return AjaxResult.warn(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
}
第二步:创建一个抽象父类ObjectService<T1, T2>接口,让其他方法继承extends
备注:T1:前端传参给后台的交互实体,例如:***Param;T2:后台传参给前端的交互实体,例如:***Vo(这个规则,可以根据自己的项目要求,具体定义,没有强制要求)
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
/**
* Title: com.sunward.common.business.service.base
* Description:基类Service
* Copyright: Copyright (c) 2024
* Company:
*
* @author :mingF
* @version :3.2.9
* @date :2024/09/4 09:11
*/
public interface ObjectService<T1, T2> {
/**
* @description : 新增
* @author : mingF
* @date : 2024/09/4 09:11
* @return :int
**/
int save(T1 entity);
/**
* @description : 修改
* @author : mingF
* @date : 2024/09/4 09:11
* @return :int
**/
int update(T1 entity);
/**
* @description : 删除
* @author : mingF
* @date : 2024/09/4 09:11
* @return :int
**/
int delete(T1 entity);
/**
* @description : 查询单条
* @author : mingF
* @date : 2024/09/4 09:11
* @return :T
**/
T2 getOne(T1 entity);
/**
* @description : 根据id查询单条
* @author : mingF
* @date : 2024/09/4 09:11
* @return :T2
**/
T2 getOneById(Long id);
/**
* @description : 查询多条
* @author : mingF
* @date : 2024/09/4 09:11
* @return :List<T2>
**/
List<T2> getListById(Long id);
/**
* @description : 查询多条
* @author : mingF
* @date : 2024/09/4 09:11
* @return :List<T2>
**/
List<T2> getList(T1 entity);
/**
* @description : 分页查询多条
* @author : mingF
* @date : 2024/09/4 09:11
* @return :IPage<T2>
**/
IPage<T2> getListByPage(Page page, T1 entity);
}
第三步:创建一个抽象父类ObjectController层,继承和实现上面编写的BaseController,ObjectService
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* Title: com.sunward.common.core.web.controller
* Description:父类控制层(继承该控制层,无需再编写增删查改方法 ,即可获得CRUD对应的方法)
* Copyright: Copyright (c) 2024
* Company:
*
* @author :mingF
* @version :3.2.9
* @date :2024/9/4 16:12
*/
public abstract class ObjectController<T1,T2,Service extends ObjectService<T1,T2>> extends BaseController {
@Autowired
Service service;
/**
* @description : 新增
* @author : mingF
* @date : 2024/9/4 16:12
* @param t
* @return :com.sunward.common.core.web.domain.AjaxResult
**/
@ApiOperation(value = "添加", notes = "添加")
@Log(title = "添加", businessType = BusinessType.INSERT)
@RequiresPermissions("add")
@PostMapping(value = "/add")
public AjaxResult add(@Validated @RequestBody T1 t) {
return toAjax(service.save(t));
}
/**
* @description : 删除
* @author : mingF
* @date : 2024/9/4 16:12
* @param t
* @return :com.sunward.common.core.web.domain.AjaxResult
**/
@ApiOperation(value = "删除", notes = "删除")
@Log(title = "删除", businessType = BusinessType.DELETE)
@RequiresPermissions("del")
@PostMapping("/del")
public AjaxResult remove(@Validated @RequestBody T1 t) {
return toAjax(service.delete(t));
}
/**
* @description :分页列表查询
* @author : mingF
* @date : 2024/9/4 16:12
* @param page
* @param t
* @return :com.sunward.common.core.response.ServerResponseEntity<com.baomidou.mybatisplus.core.metadata.IPage<T>>
**/
@ApiOperation(value = "分页列表查询", notes = "分页列表查询")
@RequiresPermissions("list")
@GetMapping("/list")
public ResponseEntity<ServerResponse<IPage<T2>>> list(Page page, T1 t) {
return ResponseEntity.ok().body(ServerResponseEntity.success(service.getListByPage(page,t)));
}
/**
* @description : 通过id查询
* @author : mingF
* @date : 2024/9/4 16:12
* @param id
* @return :org.springframework.http.ResponseEntity<com.sunward.common.core.response.ServerResponse<T>>
**/
@ApiOperation(value = "通过id查询", notes = "通过id查询")
@GetMapping("/info/{id}")
public ResponseEntity<ServerResponse<T2>> info(@PathVariable Long id) {
return ResponseEntity.ok().body(ServerResponseEntity.success(service.getOneById(id)));
}
/**
* @description : 通过id查询
* @author : mingF
* @date : 2024/9/4 16:12
* @param id
* @return :org.springframework.http.ResponseEntity<com.sunward.common.core.response.ServerResponse<T>>
**/
@ApiOperation(value = "通过id查询,返回List<T>对象", notes = "通过id查询,返回List<T>对象")
@GetMapping("/info/list/{id}")
public ResponseEntity<ServerResponse<List<T2>>> infoList(@PathVariable Long id) {
return ResponseEntity.ok().body(ServerResponseEntity.success(service.getListById(id)));
}
/**
* @description : 修改
* @author : mingF
* @date : 2024/9/4 16:12
* @param t
* @return :com.sunward.common.core.web.domain.AjaxResult
**/
@ApiOperation(value = "修改", notes = "修改")
@Log(title = "修改", businessType = BusinessType.UPDATE)
@RequiresPermissions("edit")
@PostMapping("/edit")
public AjaxResult edit(@Validated @RequestBody T1 t) {
return toAjax(service.update(t));
}
以上为止,前期的准备工作都已经准备好,现在开始写,具体的功能
第四步:创建一个抽象***Service业务Service层,extends ObjectService<***Param,***Vo>
import java.util.List;
/**
* Title:
* Description:业务service
* Copyright: Copyright (c) 2024
* Company:
*
* @author :mingF
* @version :3.2.9
* @date :2024/9/4 8:57
*/
public interface ***Service extends ObjectService<***Param,***Vo> {
/**
* @description : 这个方法,可以自己添加
* @author : mingF
* @date : 2024/9/5 10:04
* @return :null
**/
int engineerCheck(***Param param);
}
第五步:创建一个抽象***ServiceImpl层,implements 第四步定义的抽象类***Service
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.collect.Maps;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Title:
* Description:业务逻辑Service层
* Copyright: Copyright (c) 2024
* Company:
*
* @author :mingF
* @version :3.2.9
* @date :2024/9/4 9:59
*/
@Service
@Slf4j
public class AfterSaleCheckServiceImpl implements AfterSaleCheckService {
@Override
public int save(***Param entity) {
return 0;
}
@Override
public int update(***Param entity) {
return 0;
}
@Override
public int delete(***Param entity) {
return 0;
}
@Override
public ***Vo getOne(***Param entity) {
return null;
}
@Override
public ***Vo getOneById(Long id) {
return null;
}
}
@Override
public List<***Vo> getList(***Param param) {
return null;
}
@Override
public IPage<***Vo> getListByPage(Page page, ***Param param) {
return null;
}
@Override
public int engineerCheck(***Param param) {
return 0;
}
}
第六步:创建一个业务****Controller,extends ObjectController<***Param, ***Vo, ***Service>
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2024
* Company:
*
* @author :mingF
* @version :3.2.9
* @date :2024/9/4 8:54
*/
@Api(tags = "说明")
@RestController
@RequiresPermissions("数据权限标识符")
@RequestMapping(请求路径")
public class ***Controller extends ObjectController<***Param, ***Vo, ***Service> {
}
效果:
常用的增删差改如下所示
觉得写的不错的朋友,请点点赞!❤❤❤❤❤❤❤❤