效果如圖
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>-->
<!-- <!–字段命名策略過程: table標簽對應數據庫中的table表–>-->
<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()); }
}
這里以最容易出錯的刪除舉例子

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()); }
}
用戶管理接口測試不作贅述