微服务迁移记(四):公共层、接口层和实现层搭建

公共层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;
        }
    }
}

原文地址:https://www.cnblogs.com/zhouyu629/p/12326935.html

时间: 2024-10-13 11:36:43

微服务迁移记(四):公共层、接口层和实现层搭建的相关文章

微服务迁移记(三):配置中心SpringCloud Config搭建

springboot推荐使用注解方式,减少了大量的xml配置.系统的基本配置文件我选择用yml格式,相对于properties,代码更简洁(不用重复写属性),结构化更清晰一点,读取速度也应该能略快一点吧.配置文件名bootstrap.yml优先于application.yml. 分布式配置中心,主要是将配置信息保存在配置中心的本地文件或数据库或远程版本控制中心(svn.git)中.研究了一段时间阿波罗,不知道为啥虚拟机能telnet宿主mysql,但阿波罗始终提示数据库连接不上,遂放弃.进一步研

微服务迁移记(五):WEB层搭建(3)-简单的权限管理

一.redis搭建 二.WEB层主要依赖包 三.FeignClient通用接口 以上三项,参考<微服务迁移记(五):WEB层搭建(1)> 四.SpringSecurity集成 参考:<微服务迁移记(五):WEB层搭建(2)-SpringSecurity集成> 五.FreeMarker集成 参考:<微服务迁移记(五):WEB层搭建(3)-FreeMarker集成> 六.简单权限管理 实现一个简单的到按钮级权限管理,基于数据库扩展.不支持数据级权限,菜单只到二级(可以扩展至

微服务迁移记(五):WEB层搭建(1)

WEB层是最终表现层,注册至注册中心,引用接口层(不需要引用实现层).公共服务层.用户登录使用SpringSecurity,Session保存在redis中,权限管理没有用SpringSecurity那套,自己写了一个简单的菜单.按钮权限控制.我在虚拟机192.168.0.7中搭了一个redis服务. 一.redis搭建 下载redis后,在linux下启动比较简单.需要注意的是redis.config配置: 1. 如果想配置用户名密码 requirepass 123456 2. 如果不bind

微服务(入门四):identityServer的简单使用(客户端授权)

IdentityServer简介(摘自Identity官网) IdentityServer是将符合规范的OpenID Connect和OAuth 2.0端点添加到任意ASP.NET核心应用程序的中间件,通常,您构建(或重新使用)一个包含登录和注销页面的应用程序(可能还包括同意,具体取决于您的需要),IdentityServer中间件向其添加必要的协议头,以便客户端应用程序可以使用这些标准协议与之对话. 托管应用程序可以像您希望的那样复杂,但我们通常建议通过只包含与身份验证相关的UI来尽可能地保持

微服务之集成(四)下

8. 实现基于事件的异步协作方式 前面讲了一些与请求/响应模式相关的技术.那么基于事件的异步通信呢? 8.1 技术选择 主要有两个部分需要考虑:微服务发布事件机制和消费者接收事件机制. 方法一:使用消息代理 传统上来说,像RabbitMQ这样的消息代理能够处理上述两个方面的问题.生产者(producer)使用API向代理发布事件,代理也可以向消费者提供订阅服务,并且在时间发生时通知消费者. 不过需要注意的是,消息代理仅仅是中间件世界中的一个小部分而是.有一个原则需要谨记:尽量让中间件保持简单,而

Spring Cloud构建微服务架构(四)分布式配置中心

Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持.配置服务器为各应用的所有环境提供了一个中心化的外部配置.它实现了对服务端和客户端对Spring Environment和PropertySource抽象的映射,所以它除了适用于Spring构建的应用程序,也可以在任何其他语言运行的应用程序中使用.作为一个应用可以通过部署管道来进行测试或者投入生产,我们可以分别为这些环境创建配置,并且在需要迁移环境的时候获取对应环境的配置来运行. 配置服务器默认采用git来存储

从Spring Cloud到Kubernetes的微服务迁移实践

写在前面 要出发周边游(以下简称要出发)是国内知名的主打「周边游」的在线旅行网站,为了降低公司内部各个业务模块的耦合度,提高开发.交付及运维效率,我们在 2017 年就基于 Spring Cloud 完成了公司内部业务微服务化的改造,并在 2019 年实现了 Spring Cloud 至 UK8S 平台的迁移.? 本文从要出发的业务架构.Prometheus JVM 监控.基于 HPA 的峰值弹性伸缩.基于 Elastic 的APM链路跟踪及 Istio 服务治理等方面介绍了我们基于UK8S的

微服务迁移步骤建议

该怎样做,才能达成不盲目迁移服务的目标?建议按如下步骤, 1. 清理应用程序.确保应用程序具有良好的自动化测试套件,并使用了最新版本的软件包.框架和编程语言.2. 重构应用程序,把它拆分成多个模块,为模块定义清晰的 API.不要让外部代码直接触及模块内部,所有的交互应该通过模块提供的 API 来进行.3. 从应用程序中选择一个模块,并把它拆分成独立的应用程序,部署在相同的主机上.你可以从中获得一些好处,而不会带来太多的运维麻烦.不过,你仍然需要解决这两个应用之间的交互问题,虽然它们都部署在同一个

基于Spring Boot和Spring Cloud实现微服务架构学习(四)

Spring Cloud介绍 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud与Dubbo对比 提到Dubbo,我想顺便提下ESB,目前央视新华社也在用ESB来做任务编排,这里先比较下Dubbo和ESB: ESB(企业数据总线),一般采用集中式转发请求,适合大量异构系统集成,侧重任务