微服务迁移记(四):公共层、接口层和实现层搭建
公共层Nodule:zyproject-common,通用返回体、状态码枚举、自定义分页类。本来计划Entity放在common里的,后来想了下,还是放到接口层,反正其他层也都会引用接口层。
接口独立成一个Module:zyproject-api-service,定义访问接口,供实现类、表现层调用,其中Feign接口直接继承接口层,可以避免很多冗余代码
实现层Module:zyproject-api-service-impl,与数据库打交道,实现接口。
一、公共层
通用返回体是从网上抄的,ResponseData继承BaseResponse
package com.zyproject.common; /** * @program: zyproject * @description: 基本响应类封装 * @author: zhouyu(zhouyu629 @ qq.com) * @create: 2020-02-11 **/ public class BaseReponse { private int code; //响应码 private String msg; //响应消息 protected BaseReponse(){} protected BaseReponse(CodeEnum codeEnum){ this.code = codeEnum.getCode(); this.msg = codeEnum.getMsg(); } public static BaseReponse out(CodeEnum codeEnum){ return new BaseReponse(codeEnum); } public int getCode(){return code;} public void setCode(int code){this.code = code;} public String getMsg(){return msg;} public void setMsg(String msg){this.msg = msg;} }
package com.zyproject.common; /** * @program: zyproject * @description: 响应数据结构封装 * @author: zhouyu(zhouyu629 @ qq.com) * @create: 2020-02-11 **/ public class ResponseData<T> extends BaseReponse { private T data; private ResponseData(){} private ResponseData(CodeEnum codeEnum, T data){ super(codeEnum); this.data = data; } public static <T> ResponseData<T> out(CodeEnum codeEnum,T data){ return new ResponseData<T>(codeEnum,data); } public T getData(){ return data; } public void setData(T data){ this.data = data; } }
CodeEnum主要是状态码枚举
package com.zyproject.common; /** * 状态码枚举 */ public enum CodeEnum { SUCCESS(1000,"成功!"), FAIL(1001,"未知错误"), LOGINFAIL(1002,"用户名或密码错误,登录失败"), USERNOTEXIST(1003,"用户信息不存在"), TIMEOUT(1004,"会话超时"), NORIGHT(1005,"无权限"), NOTREE(1006,"未查找到对应的菜单"), NORECORDS(1007,"无记录"), ; private int code; //状态码 private String msg; //响应内容 CodeEnum(int code, String msg) { this.code = code; this.msg = msg; } public int getCode(){ return code; } public String getMsg(){ return msg; } public static String getEnumDesc(Integer value) { CodeEnum[] businessModeEnums = values(); for (CodeEnum businessModeEnum : businessModeEnums) { if (businessModeEnum.getCode() == value) { return businessModeEnum.getMsg(); } } return null; } public static Integer getEnumCode(String value) { CodeEnum[] codeEnums = values(); for (CodeEnum codeEnum : codeEnums) { if (codeEnum.getMsg() == value) { return codeEnum.getCode(); } } return null; } }
MyPager是我自己写的一个自定义分页实体类,并在WEB层实现与bootstrap分页样式结合,自定义了一个feemarker宏实现分页。WEB层再详细说明。
其他,略。
二、接口层
以模块为维度建立项目,以系统管理层为例:zyproject-api-service-system,项目类型为jar,部分代码,实体部分集成lombok,代码略。
package com.zyproject.service; import com.zyproject.common.ResponseData; import com.zyproject.entity.TreeEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; public interface ISystemService { /** * * 用户相关 * */ //用户登录方法 @RequestMapping("/userLogin") public ResponseData userLogin(@RequestParam String user_code, @RequestParam String password); //根据用户名,查找用户信息,为SpringSercrity等业务提供服务 @RequestMapping("/findByLoginname") public ResponseData findByLoginname(@RequestParam String login_name); /** * * 菜单相关 * */ //获取所有菜单列表,含有删除未删除的 @RequestMapping("/getAllTreeList") public List<TreeEntity> getAllTreeList(); //根据用户获取有权限的组织机构树 @RequestMapping("/getTreeWithUserRight") public ResponseData getTreeWithUserRight(@RequestParam int userid); //根据tree_id获取菜单实体 @RequestMapping("/getTreeByTreeId") public ResponseData getTreeByTreeId(@RequestParam int tree_id); //分页获取角色列表(状态正常) @RequestMapping("/getRoleByPage") public ResponseData getRoleByPage(@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int pagesize); //根据用户获取当前用户所有权限按钮 @RequestMapping("/getRoleTreefuncByUserid") public ResponseData getRoleTreefuncByUserid(@RequestParam int user_id); }
三、接口实现
以系统管理为例:zyproject-api-service-impl,项目类型为pom,需要以http形式发布访问,注册至consul。
需要引入zyproject-api-service-system接口项目依赖。
1. 配置文件
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: zhouyu2001cloud url: jdbc:mysql://127.0.0.1:3306/zyprojectdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 application: ## 系统管理服务 name: zyproject-api-service-system cloud: config: discovery: service-id: config-server enabled: true profile: dev label: dev consul: host: 192.168.0.7 discovery: hostname: 192.168.0.6 port: 8500 server: port: 9001 logging: level: org.springframework.jdbc.core.JdbcTemplate: DEBUG
2. SystemService实现ISystemService
package com.zyproject.service; import com.zyproject.common.CodeEnum; import com.zyproject.common.MyPager; import com.zyproject.common.ResponseData; import com.zyproject.dao.RoleDao; import com.zyproject.dao.TreeDao; import com.zyproject.dao.UserDao; import com.zyproject.entity.RoleEntity; import com.zyproject.entity.RoleTreefuncEntity; import com.zyproject.entity.TreeEntity; import com.zyproject.entity.UserEntity; import io.swagger.annotations.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * @program: zyproject * @description: 系统管理实现(客户端Feign同一服务只能定义一个,这里也把所有系统管理相关的服务放到一个 Service中) * @author: zhouyu(zhouyu629 @ qq.com) * @create: 2020-02-15 **/ @RestController public class SystemService implements ISystemService { @Autowired private UserDao userDao; @Autowired private TreeDao treeDao; @Autowired private RoleDao roleDao; @GetMapping("/userLogin") @ApiOperation("用户登录") @ApiImplicitParams({ @ApiImplicitParam(name = "user_code",value = "登录名",dataType = "String",required = true), @ApiImplicitParam(name = "password",value = "密码(32位小md5)",dataType = "String",required = true) }) @Override public ResponseData userLogin(String user_code, String password) { UserEntity userEntity = userDao.userLogin(user_code,password); return ResponseData.out(userEntity!=null? CodeEnum.SUCCESS:CodeEnum.LOGINFAIL,userEntity); } @GetMapping("/findByLoginname") @ApiOperation("根据用户名查找用户信息") @Override public ResponseData findByLoginname(String login_name) { UserEntity userEntity = userDao.findByUsername(login_name); return ResponseData.out(userEntity!=null?CodeEnum.SUCCESS:CodeEnum.USERNOTEXIST,userEntity); } @GetMapping("/getAllTreeList") @ApiOperation("查找所有的菜单树") public List<TreeEntity> getAllTreeList() { return treeDao.getAllTreeList(); } @GetMapping("/getTreeWithUserRight") @ApiOperation("根据用户获取权限菜单树") @ApiImplicitParams({ @ApiImplicitParam(name = "userid",type = "int",value = "用户id") }) @Override public ResponseData getTreeWithUserRight(@RequestParam(name = "userid") int userid) { List<TreeEntity> treeList = this.treeDao.getTreeWithUserRight(userid); return ResponseData.out(treeList!=null?CodeEnum.SUCCESS:CodeEnum.NORIGHT,treeList); } @GetMapping("/getTreeByTreeId") @ApiOperation("根据菜单ID获取对应的菜单实体") @ApiImplicitParams( @ApiImplicitParam(name = "tree_id",value = "菜单编号",dataType = "int") ) @Override public ResponseData getTreeByTreeId(@RequestParam int tree_id) { TreeEntity tree = this.treeDao.getTreeByTreeId(tree_id); return ResponseData.out(tree!=null?CodeEnum.SUCCESS:CodeEnum.NOTREE,tree); } @GetMapping("/getRoleByPage") @ApiOperation("分页获取角色列表(del_flag=0)") @ApiImplicitParams({ @ApiImplicitParam(name = "page", value = "当前页码(从1开始)", dataType = "int"), @ApiImplicitParam(name = "pagesize", value = "分页大小", dataType = "int") }) @Override public ResponseData getRoleByPage(int page, int pagesize) { MyPager pager = this.roleDao.getRoleByPage(page,pagesize); return ResponseData.out(pager!=null?CodeEnum.SUCCESS:CodeEnum.NORECORDS,pager); } @GetMapping("/getRoleTreefuncByUserid") @ApiOperation("根据用户获取所有权限按钮") @ApiImplicitParams({ @ApiImplicitParam(name = "user_id",value = "用户ID") }) @Override public ResponseData getRoleTreefuncByUserid(int user_id) { List<RoleTreefuncEntity> list = this.treeDao.getRoleTreefuncByUserid(user_id); return ResponseData.out(CodeEnum.SUCCESS,list); } }
3. Dao层,集成jdbctemplate,以UserDao为例
package com.zyproject.dao; import com.zyproject.entity.UserEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; /** * @program: zyproject * @description: 用户dao * @author: zhouyu(zhouyu629 @ qq.com) * @create: 2020-02-11 **/ @Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; //用户登录 public UserEntity userLogin(String user_code, String password){ String sql = "SELECT * FROM tb_user WHERE login_code=? AND login_password=? AND del_flag=0"; try { List<UserEntity> user = jdbcTemplate.query(sql,new Object[]{user_code,password},new BeanPropertyRowMapper(UserEntity.class)); if(user!=null){ //登录次数+1 jdbcTemplate.update("UPDATE tb_user SET login_count=login_count+1 WHERE login_code=?",user_code); } return user!=null?user.get(0):null; }catch (Exception e){ return null; } } //根据登录名,获取用户信息 public UserEntity findByUsername(String login_name){ String sql = "SELECT * FROM tb_user WHERE login_code=? AND del_flag=0"; try { List<UserEntity> users = jdbcTemplate.query(sql,new BeanPropertyRowMapper(UserEntity.class),login_name); return users!=null?users.get(0):null; }catch (Exception ex){ return null; } } }