效果如图

1.前言

根据需求,搭建一个springboot项目,分为登录注册界面,用户管理,角色管理模块
然后因为前后端分离,所以我们使用jwt作为我们用户身份凭证。

2.后端接口开发

2.1环境配置

2.11 创建springboot

2.12 导入相应的依赖+配置tkmapper插件

        <!--spring-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- lombook-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- swaggerUi-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>
        <!--引入tkMapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- test starter-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <!--druid-starter-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <!--  jwt相关-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

tkampper插件

 <plugin>
   <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.5</version>
    <configuration>
    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
    </configuration>
    <dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper</artifactId>
        <version>3.4.4</version>
    </dependency>
   </dependencies>
</plugin>

插件结构如下

2.13 配置application.yml

server:
  port: 9999
  servlet:
    context-path:

spring:
  datasource:
    druid:
    url: jdbc:mysql://localhost:3306/spring_test?characterEncoding=utf-8&serverTimezone=GMT
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
  mvc:
    view:
      prefix: /
      suffix: .jsp
mybatis:
  mapper-locations: classpath:mappers/*Mapper.xml
  type-aliases-package: com.itheima.role_user_demo.pojo

2.14 在resources下新建mappers目录和generator目录,在generator下新建generatorConfig.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- 引入数据库连接配置 -->
    <!--    <properties resource="jdbc.properties"/>-->

    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!-- 配置 GeneralDAO -->
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="com.itheima.role_user_demo.general.GeneralDao"/>
        </plugin>

        <!-- 配置数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/spring_test"
                        userId="root" password="123456">
        </jdbcConnection>

        <!-- 配置实体类存放路径 -->
        <javaModelGenerator targetPackage="com.itheima.role_user_demo.pojo" targetProject="src/main/java"/>

        <!-- 配置 XML 存放路径 -->
        <sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>

        <!-- 配置 DAO 存放路径 -->
        <javaClientGenerator targetPackage="com.itheima.role_user_demo.dao" targetProject="src/main/java" type="XMLMAPPER"/>

        <!-- 配置需要指定生成的数据库和表,% 代表所有表 -->
        <!--<table tableName="%"></table>-->
        <!-- &lt;!&ndash;字段命名策略过程: table标签对应数据库中的table表&ndash;&gt;-->
        <table tableName="sys_user" domainObjectName="User"></table>
        <table tableName="sys_role" domainObjectName="Role"></table>
        <table tableName="sys_user_role" domainObjectName="userAndRole"></table>
    </context>
</generatorConfiguration>

2.15 新建generalDao接口+配置启动类

package com.itheima.role_user_demo.general;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

public interface GeneralDao<T> extends Mapper<T>,MySqlMapper<T> {
}
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan("com.itheima.role_user_demo.dao")
public class RoleUserDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RoleUserDemoApplication.class, args);
    }

}

2.16 创建数据库

CREATE DATABASE spring_test;
USE `spring_test`;
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `roleName` varchar(50) DEFAULT NULL,
  `roleDesc` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_idnamedesc` (`id`,`roleName`,`roleDesc`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
insert  into `sys_role`(`id`,`roleName`,`roleDesc`) values (1,'院长老婆2','负责全面工作'),(2,'研究员','课程研发工作'),(3,'讲师','授课工作'),(4,'助教','协助解决学生的问题'),(5,'就业指导','讲找工作的jjjjj'),(6,'篮球教练','打酱油的');
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `password` varchar(80) DEFAULT NULL,
  `phoneNum` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
insert  into `sys_user`(`id`,`username`,`email`,`password`,`phoneNum`) values (2,'mj1234','2286170708@qq.com','8888','1876661611'),(3,'swifties270','2983593131@qq.com','123','123dffggggghh'),(3,'储飞','1314','2425','12121'),(5,'迈克尔乔丹','27228282@qq.com','4444','1282882'),(6,'吃','1123','1213','2311234'),(7,'韦德','1123','1213','2311234');
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `userId` bigint(50) NOT NULL,
  `roleId` bigint(50) NOT NULL,
  PRIMARY KEY (`userId`,`roleId`),
  KEY `roleId` (`roleId`),
  CONSTRAINT `sys_user_role_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `sys_user` (`id`),
  CONSTRAINT `sys_user_role_ibfk_2` FOREIGN KEY (`roleId`) REFERENCES `sys_role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `sys_user_role`(`userId`,`roleId`) values (22,1),(26,1),(2,2),(4,2),(22,2),(24,2),(26,2),(2,3),(27,3),(4,4),(24,4),(27,5);

点击mybatis-generator:generator 一键生成DAO,POJO层

2.17 生成swagger()

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    /*swagger会帮助我们生成接口文档
     * 1:配置生成的文档信息
     * 2: 配置生成规则*/

    /*Docket封装接口文档信息*/
    @Bean
    public Docket getDocket(){

        //创建封面信息对象
        ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder();
        apiInfoBuilder.title("志愿者服务后端接口说明")
                .description("此文档详细说明了志愿者服务项目后端接口规范....")
                .version("v 2.0.1")
                .contact(new Contact("储飞","www.baidu.com","liangge@wang.com") );
        ApiInfo apiInfo =  apiInfoBuilder.build();

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo) //指定生成的文档中的封面信息:文档标题、版本、作者
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.itheima.role_user_demo.controller"))
                .paths(PathSelectors.any())
                .build();

        return docket;
    }
}

2.18 统一结果封装

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "响应给VO对象",description = "封装接口返回给前端的数据")
public class ResultVo {

    //响应给前端的状态码
    @ApiModelProperty(value = "响应状态码",dataType = "int")
    private int code;

    //响应给前端的提示信息
    @ApiModelProperty("响应提示信息")
    private String msg;

    //响应给前端的数据
    @ApiModelProperty("响应数据")
    private Object data;
}
public class ResStatus {

    public static final int OK=10000;
    public static final int NO=10001;

    public static final int LOGIN_SUCCESS = 2000;  //认证成功
    public static final int LOGIN_FAIL_NOT = 20001; //用户未登录
    public static final int LOGIN_FAIL_OVERDUE = 20002; //用户登录失效
}

项目结构如下

2.2 业务实现

2.21 角色管理(crud)

Service层接口

public interface RoleService {
  //查找所有的角色
  public ResultVo findAll();
  //增加角色
  public ResultVo addRole(Role role);
  //修改角色
  public ResultVo updateRole(Role role);
  //根据角色id查出角色
  public ResultVo findRoleById(Long id);
  //删除角色
  public ResultVo deleteRoleById(Long id);
  //根据用户id获取角色
  public ResultVo findRolesByUserID(Long id);
}

其中的根据用户id获取角色是为了用户管理界面,查询所有用户并展示出该用户所具有的角色所服务的,需要在Rolemapper层自定义接口

@Repository
public interface RoleMapper extends GeneralDao<Role> {
    List<Role> findRoleByUserId(Long id);
}

roleMapper.xml

  <resultMap id="BaseResultMap" type="com.itheima.role_user_demo.pojo.Role">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="roleName" jdbcType="VARCHAR" property="rolename" />
    <result column="roleDesc" jdbcType="VARCHAR" property="roledesc" />
  </resultMap>
  <select id="findRoleByUserId" resultMap="BaseResultMap">
    SELECT r.id,r.roleName,r.roleDesc
    FROM sys_role r
    INNER JOIN sys_user_role ur ON r.id=ur.roleId AND ur.userId=#{id}
  </select>

Service层实现类 这里以删除角色和根据用户id查询角色举例

值得注意的是,角色的删除不能像前面的操作那么简单 由于外键约束的作用 sys_role里的数据删除了自然sys_role_user表里数据也要改变

删除有deleteByExample(example)和deleteByPrimaryKey(keyValue)两种方法,建议使用前者 tkmmaper的基本用法
@Override
   public ResultVo deleteRoleById(Long id) {
       //1.删除中间表sys_user_role 中的数据
       Example example = new Example(UserAndRole.class);
       Example.Criteria criteria = example.createCriteria();
       criteria.andEqualTo("roleid",id);
       //deleteByExample 传入的是example对象
       userAndRoleMapper.deleteByExample(example);
       //userAndRoleMapper.deleteByPrimaryKey(id);
       //2.删除sys_role表中的数据
       int i = roleMapper.deleteByPrimaryKey(id);
       if(i>0) return new ResultVo(ResStatus.OK,"success",i);
       else return new ResultVo(ResStatus.NO,"fail",null);
   }
   @Override
   public ResultVo findRolesByUserID(Long id) {
       List<Role> roles = roleMapper.findRoleByUserId(id);
       System.out.println("roles"+roles);
       return new ResultVo(ResStatus.OK,"success",roles);
   }

单元测试 选中待测类,快捷键ctrl + shift + t,选择Create New Test

controller层

@RestController
@CrossOrigin
@RequestMapping("/role")
@Api(tags = "角色管理")
public class RoleController {
    @Autowired
    private RoleService roleService;
    @ApiOperation("查看所有角色")
    @GetMapping("/findAllRole")
    public ResultVo findAllRole(){
        return roleService.findAll();
    }
    
    @PostMapping(value = "/addRole",produces="application/jsons;charset=UTF-8")
    @ApiOperation("增加角色")
    public ResultVo addRole(@RequestBody Role role) { return roleService.addRole(role); }

    @PostMapping(value = "/updateRole" , produces="application/jsons;charset=UTF-8")
    @ApiOperation("修改角色")
    public ResultVo updateRole(@RequestBody Role role) { return roleService.updateRole(role);}

    @PostMapping(value = "/delRole")
    @ApiOperation("删除角色")
    public  ResultVo deleteRole(@RequestBody Role role){ return roleService.deleteRoleById(role.getId()); }
}

接口测试 http://localhost:9990/doc.html

这里以最容易出错的删除举例子

2.22 用户管理(crud)

接口

findAll()方法的实现

 @Override
    public ResultVo findAll(){
        List<User> users = userMapper.selectAll();//这个user里是没有该用户拥有的角色
        System.out.println("user的个数"+users.size());
        for (User user : users) {
            Long id = user.getId();
            //根据用户的id获取该用户所具有的角色
            List<Role> roles = roleMapper.findRoleByUserId(id);
            user.setRoleList(roles);
        }
        return new ResultVo(ResStatus.OK,"successs",users);
    }

addUser()方法的实现

@Override
    public ResultVo addUser(User user,String roleIds){
        //前端传给后端的数据往往是字符串的格式以逗号隔开
        //1.在sys_user表中添加数据
        String[] ids = roleIds.split(",");
        List<Long>roleList=new ArrayList<>();
        for (String roleId : ids) {
            roleList.add(Long.parseLong(roleId));
        }
        int key = userMapper.insertUseGeneratedKeys(user);
        Long userId=user.getId();
//        System.out.println("userId="+userId);
        //2.获得返回的主键Id即userId,再更新sys_user_role表
        UserAndRole userAndRole=new UserAndRole();
        userAndRole.setUserid(userId);
        for (Long roleId : roleList) {
            userAndRole.setRoleid(roleId);
            userAndRoleMapper.insert(userAndRole);
        }
        return new ResultVo(ResStatus.OK,"success","null");
    }

deleteUserById方法的实现

 @Override
    public ResultVo deleteUserById(Long id) {
        //删除用户自然也会对sys_user_role产生影响
        //1.先删除sys_user_role中的数据
        Example example=new Example(UserAndRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userid",id);
        //deleteByPrimaryKey(example)
        userAndRoleMapper.deleteByExample(example);
        //2.删除sys_user表中的数据
        int i = userMapper.deleteByPrimaryKey(id);
        if(i>0) return new ResultVo(ResStatus.OK,"success",i);
        else return new ResultVo(ResStatus.NO,"fail",null);
    }

controlller层实现

@RestController
@CrossOrigin
@RequestMapping("/user")
@Api(tags="用户管理")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/findAllUser")
    @ApiOperation("查找所有用户")
    public ResultVo findAllUser(){ return userService.findAll();}

    @PostMapping("/addUser")
    @ApiOperation("增加用户")
    public ResultVo addUser(@RequestBody User user,String ids){ return userService.addUser(user,ids); }

    @PostMapping("/updateUser")
    @ApiOperation("修改用户")
    public ResultVo updateUser(@RequestBody User user){return userService.updateUser(user); }

    @PostMapping("/delUser")
    @ApiOperation("删除用户")
    public ResultVo delUser(@RequestBody User user){return userService.deleteUserById(user.getId()); }

}

用户管理接口测试不作赘述

3.前端开发