Spring boot集成Mybatis与Shiro无状态权限管理,实现RESTful风格的API

4 篇文章 0 订阅
2 篇文章 0 订阅

前言

最近一直在研究SpringBoot和Shiro框架,在百度和Google上参考了很多很多资料,发现大多数集成都是使用session来管理用户状态的,由于自己对前后端分离特别情有独钟,所以想自己搭建出一个无状态的RESTful风格的框架。研究了好几个星期,这里写一下步骤,也当自己复习一下遇到的问题。

由于内容有点多,打算分开来记录。

此框架涉及到的一些技术:

1.Spring Boot + Mybatis +Shiro

2.JWT

3.RBAC(基于角色的权限控制)

4.Redis缓存

开发环境:Ubuntu17.10 + IntelliJ IDEA + Maven3.5

测试工具:Postman

Github:https://github.com/phw-nightingale/govern

那么Let's do it!

1.准备工作

开始的时候我需要准备五张表,这五张表是基于RBAC权限管理的标准表,那么引用一张图:


具体的sql文件在Github中。这里我考虑用户和角色多对多,角色和权限多对多;角色为一系列权限的集合,用户也可以理解为一系列角色的集合。这样会好理解一些。

建好数据库后,打开IDEA开始搭建框架,File->New->Project,选择Spring Initializr,这里JDK版本一定要在1.8及以上,然后Next,填写包名和项目名,然后到框架选择界面:



按照图示选择即可。如果想用其他的数据库,在SQL界面选择对应的数据库即可。然后点击Finish,进入主界面。

进入主界面后可能会发现一个问题,那就Maven下载依赖的速度简直太慢了,那是因为Maven默认的设置是从国外的Maven镜像下载依赖,因为种种原因,有时候甚至还可能被墙,因此这里有个小技巧,修改一下Maven的配置,使用国内阿里云的Maven镜像来下载速度可成倍成倍提升(阿里可真是什么镜像都有微笑),File->Settings->搜索Maven:


可以看到有一栏用户设置文件,自己新建一个settings.xml,或者有的可以直接修改如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

  <pluginGroups>
  </pluginGroups>

  <proxies>
  </proxies>

  <servers>
  </servers>

  <mirrors>
    <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
  </mirrors>

  <profiles>
  </profiles>

</settings>

然后保存,将文件路径设置为settings.xml的路劲即可。这是你可以看到Maven正在飞快的下载依赖~

稍微配置一下application.properties文件:

#mysql
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useSSL=false
spring.datasource.username=root
spring.datasource.password=199798
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=xyz.frt.gov.govern.model

#log
#logging.level.xyz.frt.gov.govern=WARN
#logging.level.xyz.frt.gov.govern.dao=DEBUG
#logging.file=logs/spring-boot-logging.log
#logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
#logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

下面的log是我测试mybatis的时候用的,平时可以不用打开它。上面的mybatis第一个是xml文件的路径,第二个是实体类的包名。配置完后我们再pom.xml文件里加上几个依赖,再把pom.xml贴上来,有点多~

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.frt.gov</groupId>
    <artifactId>govern</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>govern</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <!--<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.3.0</version>
        </dependency>-->

        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <overwrite>false</overwrite>
                    <verbose>true</verbose>
                </configuration>
            </plugin>


        </plugins>
    </build>


</project>

这里还用到了mybatis自动生成代码的插件Mybatis Generator,新建一个generatorConfig.xml,再configuration中填入路径,overwrite最好选择false。

到了这里最好把自己项目的包结构划分清楚,我的是这样的:


由于我对Dao层和Service层都做了一些封装,所以几个实体类的代码就不贴了,直接贴Controller层的代码了,Dao层和Service层根据自己的喜好,当然Github里面都有:

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users/{id}")
    public JsonResult findUserByPrimaryKey(@PathVariable Integer id) {
        return userService.findByPrimaryKey(id);
    }
}

使用@RestController表明这是一个RESTful风格的WebService,就不用在每个方法上加@ResponseBody了。这个类里我们现在只关注findUserByPrimaryKey这个方法,效果就是当我们输入http://localhost:8080/users/1的时候能够返回id为1的用户。

在这之前最好先统一定义一下返回的Json数据格式,我也做了一个类:

/**
 * @author phw
 * @date 04-08-2018
 * @description 所有请求返回的结果类
 */
public class JsonResult {

    private Integer code = 0;

    private String msg;

    private Map<String, Object> dataMap = new HashMap<>();

    public JsonResult() {

    }

    private JsonResult(Integer code, String msg, Map<String, Object> dataMap) {
        this.code = code;
        this.msg = msg;
        this.dataMap = dataMap;
    }

    private JsonResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 成功提示
     * @param msg 提示消息
     * @return json result
     */
    public static JsonResult success(String msg) {
        return new JsonResult(AppConst.RESULT_SUCCESS, msg);
    }

    /**
     * 附带数据的成功提示
     * @param msg 提示消息
     * @param dataMap 返回的数据
     * @return json result
     */
    public static JsonResult success(String msg, Map<String, Object> dataMap) {
        return new JsonResult(AppConst.RESULT_SUCCESS, msg, dataMap);
    }

    /**
     * 错误提示
     * @param msg 提示消息
     * @return json result
     */
    public static JsonResult error(String msg) {
        return new JsonResult(AppConst.RESULT_ERROR, msg);
    }

    /**
     * 错误提示
     * @param code 错误码
     * @param msg 提示消息
     * @return json result
     */
    public static JsonResult error(Integer code, String msg) {
        return new JsonResult(code, msg);
    }

    /**getter and setter**/

}

在启动Application之前,还需要做一件事就是在Application上再加上一个注释:

@SpringBootApplication
@MapperScan("xyz.frt.gov.govern.dao")
public class GovernApplication {

    public static void main(String[] args) {
        SpringApplication.run(GovernApplication.class, args);
    }
}

意思是扫描Dao层的包名路径。

最后点击右上角的启动,看到Spring Boot的启动Logo而且没有报错的话就是启动成功了:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.1.RELEASE)

还挺好看的Q.Q

最后到Postman测试一下,如果返回的是这样的:

{
    "code": 200,
    "msg": "Success",
    "dataMap": {
        "data": {
            "id": 1,
            "username": "admin",
            "password": "admin",
            "phone": "1899728714",
            "enable": 0
        }
    }
}

那就说明恭喜你,成功啦~

今天就到这里,未完待续......

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值