Spring Boot 集成 Shiro实现权限控制,亲测可用,…
2018-11-20 03:19:50来源:博客园 阅读 ()
前提:
本文主要讲解Spring Boot 与 Shiro的集成 与权限控制的实现方式(主要以代码实现功能为主),主要用到的技术Spring Boot+Shiro+Jpa(通过Maven构建),并不会涉及到Shiro框架的源码分析
如果有想要学习Shiro框架的小伙伴可以去http://shiro.apache.org/官网自行学习,并推荐一个中文学习Shiro的网站https://www.sojson.com/shiro(感觉挺不错的)
需求说明:
通过SpringBoot+Shiro实现用户登录验证,授权,对不同用户角色访问资源进行验证,对用户权限访问资源验证,通过迭代加密方式提高用户密码的安全性
用户 and 角色表关系 多对多
角色 and 权限表关系 多对多
废话不多说直接上代码:
此项目是Maven多模块项目 码云地址 https://gitee.com/h-java/springboot-parent-demo
小伙伴们代码里的注释我已经写的很详细了,所以博客里不做讲解,直接看代码注释讲解就可以了
SQL文件
/* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50520 Source Host : localhost:3306 Source Database : shiro-demo Target Server Type : MYSQL Target Server Version : 50520 File Encoding : 65001 Date: 2018-11-15 16:59:02 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for hibernate_sequence -- ---------------------------- DROP TABLE IF EXISTS `hibernate_sequence`; CREATE TABLE `hibernate_sequence` ( `next_val` bigint(20) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of hibernate_sequence -- ---------------------------- INSERT INTO `hibernate_sequence` VALUES ('4'); INSERT INTO `hibernate_sequence` VALUES ('4'); INSERT INTO `hibernate_sequence` VALUES ('4'); -- ---------------------------- -- Table structure for permission_t -- ---------------------------- DROP TABLE IF EXISTS `permission_t`; CREATE TABLE `permission_t` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of permission_t -- ---------------------------- INSERT INTO `permission_t` VALUES ('1', 'Retrieve'); INSERT INTO `permission_t` VALUES ('2', 'Create'); INSERT INTO `permission_t` VALUES ('3', 'Update'); INSERT INTO `permission_t` VALUES ('4', 'Delete'); -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `role` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES ('1', 'user'); INSERT INTO `role` VALUES ('2', 'admin'); -- ---------------------------- -- Table structure for role_permission_t -- ---------------------------- DROP TABLE IF EXISTS `role_permission_t`; CREATE TABLE `role_permission_t` ( `pid` int(11) NOT NULL, `rid` int(11) NOT NULL, KEY `FKt2l638rvh84yplqqu7odiwhdx` (`rid`), KEY `FKh946y0ynuov5ynnrn024vapg9` (`pid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role_permission_t -- ---------------------------- INSERT INTO `role_permission_t` VALUES ('1', '1'); INSERT INTO `role_permission_t` VALUES ('1', '2'); INSERT INTO `role_permission_t` VALUES ('2', '2'); INSERT INTO `role_permission_t` VALUES ('3', '2'); INSERT INTO `role_permission_t` VALUES ('1', '3'); INSERT INTO `role_permission_t` VALUES ('2', '3'); INSERT INTO `role_permission_t` VALUES ('3', '3'); INSERT INTO `role_permission_t` VALUES ('4', '3'); -- ---------------------------- -- Table structure for role_t -- ---------------------------- DROP TABLE IF EXISTS `role_t`; CREATE TABLE `role_t` ( `id` int(11) NOT NULL, `role` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role_t -- ---------------------------- INSERT INTO `role_t` VALUES ('1', 'guest'); INSERT INTO `role_t` VALUES ('2', 'user'); INSERT INTO `role_t` VALUES ('3', 'admin'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `role` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'howie', '123456', 'user'); INSERT INTO `user` VALUES ('2', 'swit', '123456789', 'admin'); -- ---------------------------- -- Table structure for user_role_t -- ---------------------------- DROP TABLE IF EXISTS `user_role_t`; CREATE TABLE `user_role_t` ( `rid` int(11) NOT NULL, `uid` bigint(20) NOT NULL, KEY `FKe6b6umcoegdbmjws9e9y0n2jj` (`uid`), KEY `FK8lhd80hb3gbdbvdmlkn2oyprl` (`rid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_role_t -- ---------------------------- INSERT INTO `user_role_t` VALUES ('3', '2'); INSERT INTO `user_role_t` VALUES ('2', '1'); INSERT INTO `user_role_t` VALUES ('1', '3'); -- ---------------------------- -- Table structure for user_t -- ---------------------------- DROP TABLE IF EXISTS `user_t`; CREATE TABLE `user_t` ( `id` bigint(20) NOT NULL, `password` varchar(255) DEFAULT NULL, `salt` varchar(255) DEFAULT NULL, `username` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_t -- ---------------------------- INSERT INTO `user_t` VALUES ('1', 'dd531568fac3d2338bdba66b46b39fd7', '73ee684dd5a07e3b9034b02dcebf4e7c', 'hly'); INSERT INTO `user_t` VALUES ('2', '7f5e269e2f52955a0bbdfdef19281fd4', 'c6dc702282fd467c2c5481617c45a014', 'dxl'); INSERT INTO `user_t` VALUES ('3', 'edec83e7318071af89c8811536fd0a68', 'be535103fe5f98c4cef83cf24ab0d11b', 'zy');
父POM文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 6 <groupId>com.boot</groupId> 7 <artifactId>springboot-parent-demo</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <packaging>pom</packaging> 10 11 <name>springboot-parent-demo</name> 12 <description>Spring Boot Parent Demo</description> 13 14 <parent> 15 <groupId>org.springframework.boot</groupId> 16 <artifactId>spring-boot-starter-parent</artifactId> 17 <version>2.0.5.RELEASE</version> 18 <relativePath/> <!-- lookup parent from repository --> 19 </parent> 20 21 <!--编码--> 22 <properties> 23 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 24 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 25 <java.version>1.8</java.version> 26 </properties> 27 28 <!--子模块--> 29 <modules> 30 <module>sb-listener</module> 31 <module>sb-configration-file</module> 32 <module>sb-shiro</module> 33 <module>sb-shiro2</module> 34 </modules> 35 36 <!-- 版本说明:这里统一管理依赖的版本号 --> 37 <dependencyManagement> 38 <dependencies> 39 <dependency> 40 <groupId>com.example</groupId> 41 <artifactId>sb-listener</artifactId> 42 <version>0.0.1-SNAPSHOT</version> 43 </dependency> 44 </dependencies> 45 </dependencyManagement> 46 47 <!--父依赖--> 48 <dependencies> 49 <dependency> 50 <groupId>org.springframework.boot</groupId> 51 <artifactId>spring-boot-starter-thymeleaf</artifactId> 52 </dependency> 53 <dependency> 54 <groupId>org.springframework.boot</groupId> 55 <artifactId>spring-boot-starter-web</artifactId> 56 </dependency> 57 58 <dependency> 59 <groupId>org.projectlombok</groupId> 60 <artifactId>lombok</artifactId> 61 <optional>true</optional> 62 </dependency> 63 <dependency> 64 <groupId>org.springframework.boot</groupId> 65 <artifactId>spring-boot-starter-test</artifactId> 66 <scope>test</scope> 67 </dependency> 68 </dependencies> 69 70 <!--插件依赖--> 71 <build> 72 <plugins> 73 <plugin> 74 <groupId>org.springframework.boot</groupId> 75 <artifactId>spring-boot-maven-plugin</artifactId> 76 </plugin> 77 </plugins> 78 </build> 79 80 81 </project>
子模块项目sb-shiro2的POM文件:
<?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>com.example</groupId>
<artifactId>sb-shiro2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sb-shiro2</name>
<description>Spring Boot Shiro Demo 2</description>
<parent>
<groupId>com.boot</groupId>
<artifactId>springboot-parent-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.19</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
整体项目结构:
application.yml
server: port: 8088 spring: application: name: shiro datasource: url: jdbc:mysql://localhost:3306/shiro-demo username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver jpa: database: mysql showSql: true hibernate: ddlAuto: update properties: hibernate: dialect: org.hibernate.dialect.MySQL5Dialect format_sql: true
entity包
通过Jpa生成数据库表
User类
package com.example.demo.entity; import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.List; /** * Created by hly on 2018\11\14 0014. */ @Data @Entity @Table(name = "user_t") //数据库生成的表名 public class User implements Serializable{ private static final long serialVersionUID = 6469007496170509665L; /** * 用户id */ @Id @GeneratedValue private long id; /** * 用户名 */ private String username; /** * 用户密码 */ private String password; /** * yan */ private String salt; /** * 用户表和角色表的多对多关联 */ @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_role_t",joinColumns = {@JoinColumn(name = "uid")}, inverseJoinColumns = {@JoinColumn(name = "rid")}) private List<SysRole> roles; /** * 对盐进行再次加密 * @return */ public String getCredentialsSalt() { return username + salt + salt; } }
SysRole类
package com.example.demo.entity; import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.List; /** * Created by hly on 2018\11\14 0014. */ @Data @Entity @Table(name = "role_t") public class SysRole implements Serializable { private static final long serialVersionUID = 8215278487246865520L; /** * 角色id */ @Id @GeneratedValue private Integer id; /** * 角色名称 */ private String role; /** * 权限与用户的多对多关联 */ @ManyToMany @JoinTable(name = "user_role_t",joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "uid")}) List<User> users; /** * 角色与权限的多对多关联 */ @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "role_permission_t",joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "pid")}) List<SysPermission> permissions ; }
SysPermission类
package com.example.demo.entity; import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.List; /** * Created by hly on 2018\11\14 0014. */ @Data @Entity @Table(name = "role_t") public class SysRole implements Serializable { private static final long serialVersionUID = 8215278487246865520L; /** * 角色id */ @Id @GeneratedValue private Integer id; /** * 角色名称 */ private String role; /** * 权限与用户的多对多关联 */ @ManyToMany @JoinTable(name = "user_role_t",joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "uid")}) List<User> users; /** * 角色与权限的多对多关联 */ @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "role_permission_t",joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "pid")}) List<SysPermission> permissions ; }
mapper接口
package com.example.demo.dao; import com.example.demo.entity.User; import org.springframework.data.jpa.repository.JpaRepository; /** * Created by hly on 2018\11\14 0014. */ public interface UserMapper extends JpaRepository<User,Long>{ User findUserByUsername(String username); }
UserService
package com.example.demo.service; import com.example.demo.dao.UserMapper; import com.example.demo.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Created by hly on 2018\11\14 0014. */ @Service public class UserService { @Autowired private UserMapper userMapper; public User findUserByName(String username){ return userMapper.findUserByUsername(username); } public User saveUser(User user){ return userMapper.save(user); } }
Shiro包
ShiroConfig
package com.example.demo.shiro; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * Created by hly on 2018\11\14 0014. */ @Configuration public class ShiroConfig { // shiro filter @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> filterChainDefinitionMap = new HashMap<String, String>(); //登录界面,没有登录的用户访问授权的界面就会跳转到该界面 shiroFilterFactoryBean.setLoginUrl("/login"); //没有授权的资源,都可以访问,用户访问授权的资源无权限时跳转到该界面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthc"); shiroFilterFactoryBean.setSuccessUrl("/home/index"); //所有路径都拦截 filterChainDefinitionMap.put("/*", "anon"); //授权资源,只有登录了才能访问,并且有该对应权限的用户才可以访问 filterChainDefinitionMap.put("/authc/index", "authc"); filterChainDefinitionMap.put("/authc/admin", "roles[admin]"); filterChainDefinitionMap.put("/authc/renewable", "perms[Create,Update]"); filterChainDefinitionMap.put("/authc/removable", "perms[Delete]"); filterChainDefinitionMap.put("/authc/retrievable", "perms[Retrieve]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); System.out.println("shirFilter配置成功"); return shiroFilterFactoryBean; } //授权管理者 @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); return securityManager; } //shiro realm @Bean public EnceladusShiroRealm shiroRealm() { EnceladusShiroRealm shiroRealm = new EnceladusShiroRealm(); shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return shiroRealm; } //设置算法和迭代 @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName(PasswordHelper.ALGORITHM_NAME);// 散列算法 hashedCredentialsMatcher.setHashIterations(PasswordHelper.HASH_ITERATIONS);// 散列次数 return hashedCredentialsMatcher; } //密码加密 @Bean public PasswordHelper passwordHelper() { return new PasswordHelper(); } }
EnceladusShiroRealm
package com.example.demo.shiro; import com.example.demo.entity.SysPermission; import com.example.demo.entity.SysRole; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; /** * Created by hly on 2018\11\14 0014. * shiro中用户自定义登录验证和授权认证的地方(realm) */ public class EnceladusShiroRealm extends AuthorizingRealm{ @Autowired private UserService userService; /** * 授权认证 * @param principal * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { //负责装载role和permission的对象 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //获取用户名 String username = (String) principal.getPrimaryPrincipal(); //获取用户 User user = userService.findUserByName(username); //遍历角色和权限,并把名称加入到authorizationInfo中 for (SysRole role:user.getRoles()) { authorizationInfo.addRole(role.getRole()); for(SysPermission permission:role.getPermissions()) { authorizationInfo.addStringPermission(permission.getName()); } } return authorizationInfo; } /** * 登录验证 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取用户名 String username = (String)token.getPrincipal(); //查寻用户 User user = userService.findUserByName(username); //逻辑 if (user == null) { return null; } //包装对象(用户名、密码、用户Salt、抽象类CachingRealm的getName()) SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()),getName()); System.out.println("getName():"+getName()); //返回SimpleAuthenticationInfo对象 return authenticationInfo; } }
PasswordHelper
package com.example.demo.shiro; import com.example.demo.entity.User; import org.apache.shiro.crypto.RandomNumberGenerator; import org.apache.shiro.crypto.SecureRandomNumberGenerator; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; /** * Created by hly on 2018\11\14 0014. * 对密码进行迭代加密,保证用户密码的安全 */ public class PasswordHelper { //安全的随机字符 private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator(); //算法名称 public static final String ALGORITHM_NAME = "md5"; //迭代次数 public static final int HASH_ITERATIONS = 2; public void encryptPassword(User user) { //随机字符串作为用户的Salt user.setSalt(randomNumberGenerator.nextBytes().toHex()); //算法、用户密码、用户Salt、迭代次数 String newPassword = new SimpleHash(ALGORITHM_NAME,user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()),HASH_ITERATIONS).toHex(); //对用户设置新密码 user.setPassword(newPassword); } }
Controller包
AuthcController
package com.example.demo.controller; import com.example.demo.entity.User; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 验证的接口 */ @RestController @RequestMapping("authc") public class AuthcController { @GetMapping("index") public Object index() { Subject subject = SecurityUtils.getSubject(); User user = (User) subject.getSession().getAttribute("user"); return user.toString(); } @GetMapping("admin") public Object admin() { return "Welcome Admin"; } // delete @GetMapping("removable") public Object removable() { return "removable"; } // creat & update @GetMapping("renewable") public Object renewable() { return "renewable"; } @GetMapping("retrievable") public Object retrievable() {return "retrievable";} }
HomeController
package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import com.example.demo.shiro.PasswordHelper; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * 不验证的接口 */ @RestController @RequestMapping public class HomeController { @Autowired private UserService userService; @Autowired private PasswordHelper passwordHelper; @GetMapping("/login") public Object login() { return "Here is Login page"; } @GetMapping("/unauthc") public Object unauthc() { return "Here is Unauthc page"; } @GetMapping("doLogin") public Object doLogin(@RequestParam String username, @RequestParam String password) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (IncorrectCredentialsException ice) { return "password error!"; } catch (UnknownAccountException uae) { return "username error!"; } User user = userService.findUserByName(username); subject.getSession().setAttribute("user", user); return "SUCCESS"; } @GetMapping("/register") public Object register(@RequestParam String username, @RequestParam String password) { User user = new User(); user.setUsername(username); user.setPassword(password); passwordHelper.encryptPassword(user); userService.saveUser(user); return "注册用户SUCCESS"; } }
之后运行项目通过rest接口测试
localhost:8088/login localhost:8088/unauthc localhost:8088/doLogin?username=hly&password=123 等等通过controller里的接口进行运行测试就好了,看运行效果,我就不一一往下copy了
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:ORM是什么?如何理解ORM?
下一篇:Base64简单原理
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash