Controller如何写的更简化
Controller层相当于MVC中的C,也是安卓或者前端请求的接口。 首先说Controller为什么需要写的更加简化? 第一、Controller是不能复用的; 第二、即便是将Controller分类,如果Controller代码过于庞大,不利于维护; 第三、Controller中的CRUD之类的基本都是重复的,要么是返回数据,要么是返回状态码(通常定义一个ResultBean即可搞定); ? 我在第一个项目和第二个项目以及现在的项目犯了很多错误。 关于第一个项目和第二个项目的错误,今天暂不说。 第三个项目也就是现在的项目,Controller写的是过于庞大,参数表单校验都写在里面。 正常情况下,像比如参数非空校验之类的很常见,完全可以封装成一个ValidateUtils来校验,犯不着重复写了很多,虽然Hutool这个开源项目封装的StrUtils里面有对应的判断方法,但是感觉写了很多遍,着实不爽。觉得不经意间又犯了很多错误。重复写,显得代码冗余。 ? 下面以人人开源的代码生成器为例,人人开源的代码生成器生成的Controller是这样的,代码如下: @RestController @RequestMapping("/sys/menu") public class SysMenuController extends AbstractController { @Autowired private SysMenuService sysMenuService; /** * 导航菜单 */ @RequestMapping("/nav") public R nav(){ List<SysMenuEntity> menuList = sysMenuService.getUserMenuList(getUserId()); return R.ok().put("menuList",menuList); } * 所有菜单列表 @RequestMapping("/list") @RequiresPermissions("sys:menu:list"public List<SysMenuEntity> list(){ List<SysMenuEntity> menuList = sysMenuService.selectList(null); for(SysMenuEntity sysMenuEntity : menuList){ SysMenuEntity parentMenuEntity = sysMenuService.selectById(sysMenuEntity.getParentId()); if(parentMenuEntity != ){ sysMenuEntity.setParentName(parentMenuEntity.getName()); } } return menuList; } * 选择菜单(添加、修改菜单) @RequestMapping("/select") @RequiresPermissions("sys:menu:select" R select(){ //查询列表数据 List<SysMenuEntity> menuList = sysMenuService.queryNotButtonList(); 添加顶级菜单 SysMenuEntity root = new SysMenuEntity(); root.setMenuId(0L); root.setName("一级菜单"); root.setParentId(-1L); root.setOpen(true); menuList.add(root); * 菜单信息 @RequestMapping("/info/{menuId}") @RequiresPermissions("sys:menu:info"public R info(@PathVariable("menuId") Long menuId){ SysMenuEntity menu = sysMenuService.selectById(menuId); return R.ok().put("menu" * 保存 @SysLog("保存菜单") @RequestMapping("/save") @RequiresPermissions("sys:menu:save" R save(@RequestBody SysMenuEntity menu){ 数据校验 verifyForm(menu); sysMenuService.insert(menu); R.ok(); } * 修改 @SysLog("修改菜单") @RequestMapping("/update") @RequiresPermissions("sys:menu:update" R update(@RequestBody SysMenuEntity menu){ verifyForm(menu); sysMenuService.updateById(menu); * 删除 @SysLog("删除菜单") @RequestMapping("/delete") @RequiresPermissions("sys:menu:delete"public R delete(long menuId){ if(menuId <= 31){ return R.error("系统菜单,不能删除"); } 判断是否有子菜单或按钮 List<SysMenuEntity> menuList = sysMenuService.queryListParentId(menuId); if(menuList.size() > 0return R.error("请先删除子菜单或按钮"); } sysMenuService.delete(menuId); * 验证参数是否正确 */ private void verifyForm(SysMenuEntity menu){ if(StringUtils.isBlank(menu.getName())){ throw new RRException("菜单名称不能为空"); } if(menu.getParentId() == new RRException("上级菜单不能为空"菜单 if(menu.getType() == Constant.MenuType.MENU.getValue()){ (StringUtils.isBlank(menu.getUrl())){ new RRException("菜单URL不能为空"); } } 上级菜单类型 int parentType = Constant.MenuType.CATALOG.getValue(); if(menu.getParentId() != 0){ SysMenuEntity parentMenu = sysMenuService.selectById(menu.getParentId()); parentType = parentMenu.getType(); } 目录、菜单 if(menu.getType() == Constant.MenuType.CATALOG.getValue() || menu.getType() ==if(parentType != Constant.MenuType.CATALOG.getValue()){ new RRException("上级菜单只能为目录类型"); } ; } 按钮 Constant.MenuType.BUTTON.getValue()){ Constant.MenuType.MENU.getValue()){ new RRException("上级菜单只能为菜单类型" ; } } } ? 再看看我的Controller吧,代码示例如下: @RestController @RequiresAuthentication @RequestMapping("/sysMenu"class SysMenuController { @Autowired SysModuleService sysModuleService; @Autowired SysMenuService sysMenuService; @Autowired SysUserService sysUserServicec; * 菜单分页查询 * @param request * @return @GetMapping(value="/menuPagingQuery",produces="application/json;charset=utf-8") @ApiOperation(value="菜单分页查询",httpMethod="GET",notes="菜单分页查询" JSONObject modulePageQuery(HttpServletRequest request) { JSONObject json = JSONObject(); 公司编码 String companyCode = request.getParameter("companyCode"); 获取前台当前页 String currentPage = request.getParameter("pageno"); 获取前台每页显示数据 String pageSize = request.getParameter("pagesize"); 将前台通过request获取的currentPage参数转为Integer类型 Integer pageno = Integer.parseInt(currentPage.trim()); 将前台通过request获取的pageSize参数转为Integer类型 Integer pagesize = Integer.parseInt(pageSize.trim()); 将条件放入Map中 Map<String,Object> conditionMap = new HashMap<String,Object>(); conditionMap.put("companyCode"pagesize); conditionMap.put("size"调用查询集合数据方法 List<SysMenu> list = sysMenuService.queryMenuPagingListInfo(conditionMap); int count =sysMenuService.queryMenuPagingTotalCount(conditionMap); 总页数计算 初始化为0 int totalPageCount = 0; if ( count % pagesize == 0 ) { totalPageCount = count / pagesize; } else { totalPageCount = count / pagesize + 1; } 判断集合数据是否为空 if(!list.isEmpty()) { Page<SysMenu> page = new Page<SysMenu>(); page.setDatas(list); page.setTotalno(totalPageCount); page.setTotalsize(count); json.put(CommonEnum.RETURN_MSG,"获得菜单信息"); json.put("page"); } { json.put(CommonEnum.RETURN_MSG,"暂无数据"); json.put(CommonEnum.RETURN_CODE,"222221" json; } * 根据模块编码获得对应的菜单信息 * moduleCodes * @GetMapping(value = "/getMenuListInfo",1)">) @ApiOperation(value="根据模块编码获得对应的菜单信息",notes="根据模块编码获得对应的菜单信息" JSONObject getMenuListInfo(String moduleCodes) { JSONObject json = JSONObject(); try { StrUtil.isEmpty(moduleCodes)) { EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>(); wrapper.eq("module_codes" sysMenuService.selectList(wrapper); sysMenuList.isEmpty()) { json.put(CommonEnum.RETURN_CODE,1)">); json.put(CommonEnum.RETURN_MSG,"获得该模块下的所有菜单信息"); json.put("sysMenuList" { json.put(CommonEnum.RETURN_CODE,"没有数据"); } } { json.put(CommonEnum.RETURN_CODE,"333333"); json.put(CommonEnum.RETURN_MSG,"参数异常:参数不能为空"); } } catch (Exception e) { json.put(CommonEnum.RETURN_CODE,"444444"); json.put(CommonEnum.RETURN_MSG,"其他异常"); } json; } * 新增菜单 * @PostMapping(value = "/addMenu",1)">) @ApiOperation(value="新增菜单",httpMethod="POST",notes="新增菜单" JSONObject addMenu(@RequestBody MenuDto menuDto) { JSONObject json = JSONObject(); { 参数非空校验 StrUtil.isEmptyIfStr(menuDto)) { 根据用户编号获取操作用户信息 EntityWrapper<SysUser> wrapper =new EntityWrapper<SysUser>(); wrapper.eq("user_code" sysUserServicec.selectOne(wrapper); 根据模块名字获取对应模块信息 EntityWrapper<SysModule> wrapper2 = new EntityWrapper<SysModule>(); wrapper2.eq("module_name" sysModuleService.selectOne(wrapper2); SysMenu menu = SysMenu(); menu.setMenuCode(String.valueOf(RandomUtil.randomInt(666666))); menu.setMenuName(menuDto.getMenuName()); menu.setMenuHref(menuDto.getMenuHref()); menu.setMenuIcon(menuDto.getMenuIcon()); menu.setMenuType(menuDto.getMenuType()); menu.setCreateBy(user.getUserName()); menu.setIsShow(menuDto.getIsShow()); menu.setTreeSort(menuDto.getTreeSort()); menu.setSysCode(module.getModuleCode()); menu.setModuleCodes(module.getModuleCode()); menu.setPermission(menuDto.getPermission()); menu.setCreateDate(DateUtil.date().toString()); menu.setUpdateBy(user.getUserName()); menu.setUpdateDate(DateUtil.date().toString()); menu.setRemarks(menuDto.getRemarks()); 调用添加逻辑 boolean isAddMenu = sysMenuService.insert(menu); (isAddMenu) { json.put(CommonEnum.RETURN_CODE,1)">); json.put(CommonEnum.RETURN_MSG,"添加菜单成功"); } { json.put(CommonEnum.RETURN_CODE,"添加菜单失败"); } } { json.put(CommonEnum.RETURN_CODE,"222222"); } } (Exception e) { json.put(CommonEnum.RETURN_CODE,1)"> json; } * 根据菜单编号获取对应的菜单信息 * menuCode * @GetMapping(value="/selectByMenuCodeInfo",1)">) @ApiOperation(value="根据菜单编号获取对应的菜单信息",notes="根据菜单编号获取对应的菜单信息" JSONObject selectByMenuCodeInfo(String menuCode) { JSONObject json = StrUtil.isEmpty(menuCode)) { EntityWrapper<SysMenu> wrapper = (); wrapper.eq("menu_code" sysMenuService.selectOne(wrapper); if(menu!=) { json.put("menu"); }); } }); } } json; } * 删除菜单 * @PostMapping(value="/deleteMenuInfo",1)">) @ApiOperation(value="删除菜单",notes="删除菜单" JSONObject deleteMenuInfo(String menuCode) { JSONObject json = StrUtil.isEmpty(menuCode)) { boolean isDelete = sysMenuService.deleteById(menuCode); (isDelete) { json.put(CommonEnum.RETURN_CODE,"删除成功"); } (Exception e) { json.put(CommonEnum.RETURN_CODE,1)"> json; } * 修改菜单 * @PostMapping(value = "/modifyMenu",1)">) @ApiOperation(value="修改菜单",notes="修改菜单" JSONObject modifyMenu(@RequestBody MenuDto menuDto) { JSONObject json = SysMenu(); menu.setMenuCode(menuDto.getMenuCode()); menu.setMenuName(menuDto.getMenuName()); menu.setMenuHref(menuDto.getMenuHref()); menu.setMenuIcon(menuDto.getMenuIcon()); menu.setMenuType(menuDto.getMenuType()); menu.setIsShow(menuDto.getIsShow()); menu.setTreeSort(menuDto.getTreeSort()); menu.setSysCode(module.getModuleCode()); menu.setPermission(menuDto.getPermission()); menu.setModuleCodes(module.getModuleCode()); menu.setUpdateBy(user.getUserName()); menu.setUpdateDate(DateUtil.date().toString()); menu.setRemarks(menuDto.getRemarks()); 调用修改逻辑 sysMenuService.updateById(menu); ); } } * 图标存储(以Cookie的形式保存) * icon * response * @GetMapping(value="iconStorage",1)">) @ApiOperation(value="图标存储",notes="图标存储" JSONObject iconStorage(String icon,HttpServletResponse response) { JSONObject json = StrUtil.isEmpty(icon)) { CookieUtils.setCookie(response,"icon",icon,3600); json.put(CommonEnum.RETURN_CODE,"图标存储成功"); }); } } json; } } ? 两者比较,前者对重复的代码和一些常见的参数校验和异常捕捉拦截做了很好的封装,后者则相反。俗话说:向好同学学习。 下面我将贴一下上面的封装类: R.java import java.util.HashMap; java.util.Map; class R extends HashMap<String,1)"> { static final long serialVersionUID = 1L; R() { put("code",0); put("msg","success"); } static R error() { return error(500,"未知异常,请联系管理员" R error(String msg) { return error(500static R error(int code,String msg) { R r = R(); r.put("code" r; } R ok(String msg) { R r = R(); r.put("msg" r; } static R ok(Map<String,1)"> map) { R r = R(); r.putAll(map); R ok() { return R(); } @Override R put(String key,Object value) { super.put(key,value); this; } } ? RRException.java import io.renren.common.utils.R;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 异常处理器
*
* @author Mark sunlightcs@gmail.com
* @since 1.0.0 2016-10-27
*/
@RestControllerAdvice
public class RRExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 处理自定义异常
*/
@ExceptionHandler(RRException.class)
public R handleRRException(RRException e){
R r = new R();
r.put("code",e.getCode());
r.put("msg",e.getMessage());
return r;
}
@ExceptionHandler(DuplicateKeyException.class)
public R handleDuplicateKeyException(DuplicateKeyException e){
logger.error(e.getMessage(),e);
return R.error("数据库中已存在该记录");
}
@ExceptionHandler(AuthorizationException.class)
public R handleAuthorizationException(AuthorizationException e){
logger.error(e.getMessage(),e);
return R.error("没有权限,请联系管理员授权");
}
@ExceptionHandler(Exception.class)
public R handleException(Exception e){
logger.error(e.getMessage(),e);
return R.error();
}
}
? 小结: 本次讲解的是如何将Controller写的更加简洁,同时也不要忘记一点,前面说到Controller的代码不能过于庞大,那么service可以稍微庞大点,前提是在业务需要的情况下。当然了,最好还是那句话,代码能写短点就短点,利于维护,提高性能。当然了,凡事没有绝对,不一定代码写的长,执行性能就差。这就需要开发者们实际开发中多注意。同时关于代码规范,可以参考借鉴《阿里巴巴Java开发手册》,毕竟是咱们中国人自己开创的。另外最近再看一本新书叫《码出高效》,翻了几章,觉得挺不错的,在此推荐给大家。 ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |