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 != null){
sysMenuEntity.setParentName(parentMenuEntity.getName());
}
} return menuList;
} /**
* 选择菜单(添加、修改菜单)
*/
@RequestMapping("/select")
@RequiresPermissions("sys:menu:select")
public 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); return R.ok().put("menuList", menuList);
} /**
* 菜单信息
*/
@RequestMapping("/info/{menuId}")
@RequiresPermissions("sys:menu:info")
public R info(@PathVariable("menuId") Long menuId){
SysMenuEntity menu = sysMenuService.selectById(menuId);
return R.ok().put("menu", menu);
} /**
* 保存
*/
@SysLog("保存菜单")
@RequestMapping("/save")
@RequiresPermissions("sys:menu:save")
public R save(@RequestBody SysMenuEntity menu){
//数据校验
verifyForm(menu); sysMenuService.insert(menu); return R.ok();
} /**
* 修改
*/
@SysLog("修改菜单")
@RequestMapping("/update")
@RequiresPermissions("sys:menu:update")
public R update(@RequestBody SysMenuEntity menu){
//数据校验
verifyForm(menu); sysMenuService.updateById(menu); return R.ok();
} /**
* 删除
*/
@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() > 0){
return R.error("请先删除子菜单或按钮");
} sysMenuService.delete(menuId); return R.ok();
} /**
* 验证参数是否正确
*/
private void verifyForm(SysMenuEntity menu){
if(StringUtils.isBlank(menu.getName())){
throw new RRException("菜单名称不能为空");
} if(menu.getParentId() == null){
throw new RRException("上级菜单不能为空");
} //菜单
if(menu.getType() == Constant.MenuType.MENU.getValue()){
if(StringUtils.isBlank(menu.getUrl())){
throw 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() == Constant.MenuType.MENU.getValue()){
if(parentType != Constant.MenuType.CATALOG.getValue()){
throw new RRException("上级菜单只能为目录类型");
}
return ;
} //按钮
if(menu.getType() == Constant.MenuType.BUTTON.getValue()){
if(parentType != Constant.MenuType.MENU.getValue()){
throw new RRException("上级菜单只能为菜单类型");
}
return ;
}
}
}

再看看我的Controller吧,代码示例如下:

@RestController
@RequiresAuthentication
@RequestMapping("/sysMenu")
public class SysMenuController {
@Autowired
private SysModuleService sysModuleService; @Autowired
private SysMenuService sysMenuService; @Autowired
private SysUserService sysUserServicec; /**
* 菜单分页查询
* @param request
* @return
*/
@GetMapping(value="/menuPagingQuery",produces="application/json;charset=utf-8")
@ApiOperation(value="菜单分页查询",httpMethod="GET",notes="菜单分页查询")
public JSONObject modulePageQuery(HttpServletRequest request) { JSONObject json = new 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", companyCode);
conditionMap.put("start", (pageno-1)*pagesize);
conditionMap.put("size", pagesize); //调用查询集合数据方法
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", page);
json.put(CommonEnum.RETURN_CODE, "000000"); }else { json.put(CommonEnum.RETURN_MSG, "暂无数据");
json.put(CommonEnum.RETURN_CODE, "111111");
} return json; } /**
* 根据模块编码获得对应的菜单信息
* @param moduleCodes
* @return
*/
@GetMapping(value = "/getMenuListInfo",produces="application/json;charset=utf-8")
@ApiOperation(value="根据模块编码获得对应的菜单信息",httpMethod="GET",notes="根据模块编码获得对应的菜单信息")
public JSONObject getMenuListInfo(String moduleCodes) {
JSONObject json = new JSONObject();
try { if(!StrUtil.isEmpty(moduleCodes)) { EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
wrapper.eq("module_codes", moduleCodes);
List<SysMenu> sysMenuList = sysMenuService.selectList(wrapper); if(!sysMenuList.isEmpty()) {
json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "获得该模块下的所有菜单信息");
json.put("sysMenuList", sysMenuList);
json.put("menuSize", sysMenuList.size()); }else {
json.put(CommonEnum.RETURN_CODE, "111111");
json.put(CommonEnum.RETURN_MSG, "没有数据");
} }else {
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, "其他异常");
} return json;
} /**
* 新增菜单
* @return
*/
@PostMapping(value = "/addMenu",produces="application/json;charset=utf-8")
@ApiOperation(value="新增菜单",httpMethod="POST",notes="新增菜单")
public JSONObject addMenu(@RequestBody MenuDto menuDto) {
JSONObject json = new JSONObject(); try { //参数非空校验
if(!StrUtil.isEmptyIfStr(menuDto)) { //根据用户编号获取操作用户信息
EntityWrapper<SysUser> wrapper =new EntityWrapper<SysUser>();
wrapper.eq("user_code", menuDto.getUserCode());
SysUser user = sysUserServicec.selectOne(wrapper); //根据模块名字获取对应模块信息
EntityWrapper<SysModule> wrapper2 = new EntityWrapper<SysModule>();
wrapper2.eq("module_name", menuDto.getModuleName());
SysModule module = sysModuleService.selectOne(wrapper2); SysMenu menu = new 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); if(isAddMenu) {
json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "添加菜单成功");
}else {
json.put(CommonEnum.RETURN_CODE, "111111");
json.put(CommonEnum.RETURN_MSG, "添加菜单失败");
} }else { json.put(CommonEnum.RETURN_CODE, "222222");
json.put(CommonEnum.RETURN_MSG, "参数校验异常");
} } catch (Exception e) { json.put(CommonEnum.RETURN_CODE, "333333");
json.put(CommonEnum.RETURN_MSG, "其他异常");
} return json;
} /**
* 根据菜单编号获取对应的菜单信息
* @param menuCode
* @return
*/
@GetMapping(value="/selectByMenuCodeInfo",produces="application/json;charset=utf-8")
@ApiOperation(value="根据菜单编号获取对应的菜单信息",httpMethod="GET",notes="根据菜单编号获取对应的菜单信息")
public JSONObject selectByMenuCodeInfo(String menuCode) { JSONObject json = new JSONObject(); try { if(!StrUtil.isEmpty(menuCode)) {
EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
wrapper.eq("menu_code", menuCode);
SysMenu menu = sysMenuService.selectOne(wrapper); if(menu!=null) { json.put("menu", menu);
json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "获取菜单信息成功"); }else {
json.put(CommonEnum.RETURN_CODE, "1111111");
json.put(CommonEnum.RETURN_MSG, "获取菜单信息失败");
}
}else {
json.put(CommonEnum.RETURN_CODE, "222222");
json.put(CommonEnum.RETURN_MSG, "参数异常");
} } catch (Exception e) { json.put(CommonEnum.RETURN_CODE, "333333");
json.put(CommonEnum.RETURN_MSG, "其他异常");
} return json;
} /**
* 删除菜单
* @param menuCode
* @return
*/
@PostMapping(value="/deleteMenuInfo",produces="application/json;charset=utf-8")
@ApiOperation(value="删除菜单",httpMethod="POST",notes="删除菜单")
public JSONObject deleteMenuInfo(String menuCode) { JSONObject json = new JSONObject(); try { if(!StrUtil.isEmpty(menuCode)) { boolean isDelete = sysMenuService.deleteById(menuCode);
if(isDelete) {
json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "删除成功");
}else {
json.put(CommonEnum.RETURN_CODE, "111111");
json.put(CommonEnum.RETURN_MSG, "删除失败");
}
}else {
json.put(CommonEnum.RETURN_CODE, "222222");
json.put(CommonEnum.RETURN_MSG, "参数异常");
} } catch (Exception e) { json.put(CommonEnum.RETURN_CODE, "333333");
json.put(CommonEnum.RETURN_MSG, "其他异常");
} return json; } /**
* 修改菜单
* @return
*/
@PostMapping(value = "/modifyMenu",produces="application/json;charset=utf-8")
@ApiOperation(value="修改菜单",httpMethod="POST",notes="修改菜单")
public JSONObject modifyMenu(@RequestBody MenuDto menuDto) {
JSONObject json = new JSONObject(); try { //参数非空校验
if(!StrUtil.isEmptyIfStr(menuDto)) { //根据用户编号获取操作用户信息
EntityWrapper<SysUser> wrapper =new EntityWrapper<SysUser>();
wrapper.eq("user_code", menuDto.getUserCode());
SysUser user = sysUserServicec.selectOne(wrapper); //根据模块名字获取对应模块信息
EntityWrapper<SysModule> wrapper2 = new EntityWrapper<SysModule>();
wrapper2.eq("module_name", menuDto.getModuleName());
SysModule module = sysModuleService.selectOne(wrapper2); SysMenu menu = new 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()); //调用修改逻辑
boolean isAddMenu = sysMenuService.updateById(menu); if(isAddMenu) {
json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "修改菜单成功");
}else {
json.put(CommonEnum.RETURN_CODE, "111111");
json.put(CommonEnum.RETURN_MSG, "修改菜单失败");
} }else { json.put(CommonEnum.RETURN_CODE, "222222");
json.put(CommonEnum.RETURN_MSG, "参数校验异常");
} } catch (Exception e) { json.put(CommonEnum.RETURN_CODE, "333333");
json.put(CommonEnum.RETURN_MSG, "其他异常");
} return json;
} /**
* 图标存储(以Cookie的形式保存)
* @param icon
* @param response
* @return
*/
@GetMapping(value="iconStorage",produces="application/json;charset=utf-8")
@ApiOperation(value="图标存储",httpMethod="GET",notes="图标存储")
public JSONObject iconStorage(String icon,HttpServletResponse response) {
JSONObject json = new JSONObject(); try { if(!StrUtil.isEmpty(icon)) { CookieUtils.setCookie(response, "icon", icon, 3600); json.put(CommonEnum.RETURN_CODE, "000000");
json.put(CommonEnum.RETURN_MSG, "图标存储成功");
}else {
json.put(CommonEnum.RETURN_CODE, "1111111");
json.put(CommonEnum.RETURN_MSG, "图标存储失败");
}
} catch (Exception e) { json.put(CommonEnum.RETURN_CODE, "222222");
json.put(CommonEnum.RETURN_MSG, "其他异常");
} return json; } }

两者比较,前者对重复的代码和一些常见的参数校验和异常捕捉拦截做了很好的封装,后者则相反。俗话说:向好同学学习。

下面我将贴一下上面的封装类:

R.java

import java.util.HashMap;
import java.util.Map; public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L; public R() {
put("code", 0);
put("msg", "success");
} public static R error() {
return error(500, "未知异常,请联系管理员");
} public static R error(String msg) {
return error(500, msg);
} public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
} public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
} public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
} public static R ok() {
return new R();
} @Override
public R put(String key, Object value) {
super.put(key, value);
return 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开发手册》,毕竟是咱们中国人自己开创的。另外最近再看一本新书叫《码出高效》,翻了几章,觉得挺不错的,在此推荐给大家。

Controller如何写的更简化的更多相关文章

  1. 如何在 ASP.NET Core 中写出更干净的 Controller

    你可以遵循一些最佳实践来写出更干净的 Controller,一般我们称这种方法写出来的 Controller 为瘦Controller,瘦 Controller 的好处在于拥有更少的代码,更加单一的职 ...

  2. Controller里写自己需要的Action,参数的名字必须和路由设置的参数名一致

    Controller里写自己需要的Action,参数的名字必须和路由设置的参数名一致,如果参数不一致,传过去为null

  3. java 11 移除的一些其他内容,更简化的编译运行程序,Unicode 10,移除了不太使用的JavaEE模块和CORBA技术,废除Nashorn javascript引擎,不建议使用Pack200 相关api

    移除的一些其他内容 移除项 移除了com.sun.awt.AWTUtilities 移除了sun.misc.Unsafe.defineClass, 使用java.lang.invoke.MethodH ...

  4. 使用Groovy+Spock轻松写出更简洁的单测

    当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...

  5. SSD 为什么顺序写比随机写性能更好?

    SSD以Page为单位做读写,以Block为单位做垃圾回收,Page一般有16KB大小,Block一般有几十MB大小,SSD写数据的逻辑是: 1)将该块数据所在的Page读出 2)修改该Page中该块 ...

  6. [label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码

    7 steps to better JavaScript 原文链接: http://www.creativebloq.com/netmag/7-steps-better-javascript-5141 ...

  7. Groovy系列-groovy比起Java--有哪些地方写起来更舒服?

    groovy比起java-有哪些地方写起来更舒服 java发展缓慢,语法落后冗余 说起java,其实java挺好的,java现在的性能也不错,但是,java的语法显然比较落后,而且冗余,getter/ ...

  8. 用Less定义常用的CSS3效果函数及常用颜色搭配(让CSS写起来更有趣)

    定义圆角及调用 /* 定义圆角 @radius 圆角大小 */ .round(@radius:5px){ border-radius:@radius; -webkit-border-radius: @ ...

  9. 如何让你的JS代码写的更漂亮

    感觉这篇文章总结的js的规范写法不错,拿来收藏.转自:https://mp.weixin.qq.com/s/AtR94IL9BW9EXOTnKOilmA 1. 按强类型风格写代码 JS是弱类型的,但是 ...

随机推荐

  1. 一、JDBC基础示例

    一.简介 JDBC全称叫做Java database connectivity,直译为Java语言的数据库连接.它主要针对于支持结构化查询语言(SQL)的数据源,与Java程序连接并操作数据. JDB ...

  2. java加载redis以及基本操作

    前言: Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server).Redis的键值可以包括字符串(st ...

  3. python 实现websocket

    python中websocket需要我们自己实现握手代码,流程是这样:服务端启动websocket服务,并监听.当客户端连接过来时,(需要我们自己实现)服务端就接收客户端的请求数据,拿到请求头,根据请 ...

  4. [转]Tips——Chrome DevTools - 25 Tips and Tricks

    Chrome DevTools - 25 Tips and Tricks 原文地址:https://www.keycdn.com/blog/chrome-devtools 如何打开? 1.从浏览器菜单 ...

  5. csharp:search and Compare string

    /// <summary> /// 涂聚文 /// 2011 捷为工作室 /// 缔友计算机信息技术有限公司 /// </summary> /// <param name ...

  6. ajax回调中执行window.open被拦截的解决办法

    From:https://blog.csdn.net/winy_lm/article/details/60959751 ajax async设为false即同步调用 //去支付function got ...

  7. 域模型中的实体类分为四种类型:VO、DTO、DO、PO

    经常会接触到VO,DO,DTO的概念,本文从领域建模中的实体划分和项目中的实际应用情况两个角度,对这几个概念进行简析. 得出的主要结论是:在项目应用中,VO对应于页面上需要显示的数据(表单),DO对应 ...

  8. webform 使用log4net配置

    效果: web.config配置 <configuration> <configSections> <!--log4net日志记录--> <section n ...

  9. C# 后台解析json,简单方法 字符串序列化为对象,取值

    如果后台是一个JSON的字符串格式如下: string str = "{\"Success\":true,\"Msg\":\"成功!\&qu ...

  10. (C#) 多线程访问探讨,如果保证线程安全?

    先抛出几点疑问: 1. 多个线程同时访问同一个“值类型变量“(value type, stored in stack), 如果保证安全访问? 2. 多个线程同时访问同一个“引用类型变量“(refere ...