初衷:我在网上想找整合springboot+mybatis+shiro并且多角色认证的博客,发现找了好久也没有找到想到的,现在自己会了,就打算写个博客分享出去,希望能帮到你。
原创不易,请点赞支持!

该项目不会将过多基础,直接实战,比较使用于有一点基础的, 并且想整合springboot+mybatis+shiro的朋友们。

代码和数据库sql都放在github,链接如下:https://github.com/zhiyuwyu/springboot-mybatis-shiro.git

一篇搞定 SpringBoot+Mybatis+Shiro 实现多角色权限管理

  • 1、了解需求
    • 1.1、了解页面
    • 1.2、需求
  • 2、准备数据库环境
  • 3、编写代码
    • 3.1、新建SpringBoot 工程项目
    • 3.2、添加如下依赖
    • 3.3、编写代码连接数据库并测试
      • 3.3.1、配置数据库信息
      • 3.3.2、编写实体类 entity
      • 3.3.3、mapper
      • 3.3.4、service
    • 3.4、编写页面
    • 3.5、编写 shiro 的有关配置
    • 3.6、编写Controller层代码
  • 4、测试
    • 4.0、游客访问
    • 4.1、测试无用户登录
    • 4.2、测试密码不正确登录
    • 4.3、测试 rootA用户正确登录
    • 4.4、测试adminA用户正确登录
    • 4.5、测试userA用户正确登录
  • 5、结语

1、了解需求

1.1、了解页面

登录页面如下

首页页面如下

分别点击添加、删除、查询、测试超链接,展示的内容如下

1.2、需求

  • 首页页面必须登录成功之后才能访问
  • 所有用户、游客等都可访问登录页面、测试页面,无需登录
  • 拥有 root 角色的用户可以访问所有页面,包括添加页面、删除页面、查询页面、测试页面等
  • 拥有admin 角色的用户可以访问添加页面,查询页面、测试页面,除了删除页面不能访问
  • 拥有 user 角色的用户可以访问 查询页面、测试页面,除了添加页面、删除页面不能访问

2、准备数据库环境

新建一个test数据库,创建两个表(role、user)并插入数据,sql 如下

/*Navicat Premium Data TransferSource Server         : LocalHostSource Server Type    : MySQLSource Server Version : 50731Source Host           : localhost:3306Source Schema         : testTarget Server Type    : MySQLTarget Server Version : 50731File Encoding         : 65001Date: 12/07/2021 21:08:51
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (`id` int(2) NOT NULL AUTO_INCREMENT,`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'root', '超级管理员');
INSERT INTO `role` VALUES (2, 'admin', '管理员');
INSERT INTO `role` VALUES (3, 'user', '普通用户');-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`id` int(10) NOT NULL AUTO_INCREMENT,`username` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,`role_id` int(3) NOT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'rootA', '123456', 1);
INSERT INTO `user` VALUES (2, 'adminA', '123456', 2);
INSERT INTO `user` VALUES (3, 'userA', '123456', 3);
INSERT INTO `user` VALUES (4, 'userB', '123456', 3);SET FOREIGN_KEY_CHECKS = 1;

role 表数据如下:

user 表数据如下:

3、编写代码

3.1、新建SpringBoot 工程项目


3.2、添加如下依赖

全部依赖如下

<!-- thymeleaf -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency>
<!-- Spring对Shiro支持 -->
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.7.1</version>
</dependency>
<!--test单元测试-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.14</version>
</dependency>

3.3、编写代码连接数据库并测试

3.3.1、配置数据库信息

把 application.properties 文件修改成 application.yml,并添加如下内容

spring:datasource:username: root password: 123456 url: jdbc:mysql://localhost:3306/test
# 打印sql语句
logging:level:com:huang:shiro1:mapper: debug

3.3.2、编写实体类 entity

新建一个entity 包,分别添加下面两个实体类

User.java

package com.huang.springbootmybatisshiro.entity;
import lombok.Data;
import java.io.Serializable;
/*** (User)实体类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {private static final long serialVersionUID = 227751358530931042L;private Integer id;private String username;private String password;private Integer roleId;private Role role;
}

Role.java

package com.huang.springbootmybatisshiro.entity;
import lombok.Data;
import java.io.Serializable;
/*** (Role)实体类*/
@Data
public class Role implements Serializable {private static final long serialVersionUID = -76407922564857637L;private Integer id;private String name;private String remark;}

3.3.3、mapper

新建一个 mapper 包,分别创建下面两个文件

UserMapper.java

public interface UserMapper {/*** 根据 Username 查询单条数据** @param username* @return*/User queryByUsername(@Param("username") String username);}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huang.springbootmybatisshiro.mapper.UserMapper"><resultMap type="com.huang.springbootmybatisshiro.entity.User" id="UserMap"><result property="id" column="id" jdbcType="INTEGER"/><result property="username" column="username" jdbcType="VARCHAR"/><result property="password" column="password" jdbcType="VARCHAR"/><result property="roleId" column="role_id" jdbcType="INTEGER"/></resultMap><resultMap id="UserMapWithRole" type="com.huang.springbootmybatisshiro.entity.User" extends="UserMap"><collection property="role" ofType="com.huang.springbootmybatisshiro.entity.Role"><id property="id" column="rid"></id><result property="name" column="rname"></result><result property="remark" column="rremark"></result></collection></resultMap><select id="queryByUsername" resultMap="UserMapWithRole">selectu.*,r.id rid,r.name rname,r.remark rremarkfrom test.user u,test.role rwhere u.role_id=r.id<if test="username != null and username != ''">and username = #{username}</if></select></mapper>

注意:

UserMapper.xml 和UserMapper.java 文件写在同一目录下,需在pom.xml文件添加如下内容

<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

并且在启动类中添加注解@mapperscan 全局扫描 mapper 文件

@SpringBootApplication
@MapperScan(basePackages = "com.huang.springbootmybatisshiro.mapper")
public class SpringbootMybatisShiroApplication {public static void main(String[] args) {SpringApplication.run(SpringbootMybatisShiroApplication.class, args);}
}

3.3.4、service

新建一个包service,并添加 Userservice.java 文件如下

@Service
public class UserService {@AutowiredUserMapper userMapper;public User queryByUsername(String username) {return userMapper.queryByUsername(username);}
}

3.3.4 测试是否可以正常获取数据库信息

@SpringBootTest
class SpringbootMybatisShiroApplicationTests {@AutowiredUserService userService;@Testvoid contextLoads() {User rootA = userService.queryByUsername("rootA");System.out.println("=====================================");System.out.println("rootA = " + rootA);}}

如果输入如下数据则成功,就可以进行下一步了

3.4、编写页面

在resources目录下新建文件夹templates(有就不用了),在templates 下添加如下页面

  • add.html 添加页面
  • delete.html 删除页面
  • index.html 首页页面
  • login.html 登录页面
  • query.html 查询页面
  • test.html 测试页面
  • unauthorized.html 未授权页面

add.html

<!DOCTYPE html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>add</title>
</head>
<body>
<h1>添加页面</h1>
</body>
</html>

delete.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>update</title>
</head>
<body>
<h1>删除页面</h1>
</body>
</html>

index.html

<!DOCTYPE html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>首页</title>
</head>
<body>
<h1>首页</h1>
进入用户添加页面: <a href="add">添加页面</a><br/>
进入用户删除页面: <a href="delete">删除页面</a><br/>
进入用户查询页面: <a href="query">查询页面</a><br/>
进入用户测试页面: <a href="test">测试页面</a><br/>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>login</title>
</head>
<body>
<h1>登录页面</h1>
<h3 th:text="${msg}" style="color: red"></h3>
<form action="login" method="post">用户名:<input type="text" name="username"><br>密码:<input type="text" name="password"><br><input type="submit" value="submit">
</form>
</body>
</html>

query.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>query</title>
</head>
<body>
<h1>查询页面</h1>
</body>
</html>

test.html

<!DOCTYPE html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>测试页面</title>
</head>
<body>
<h1>测试页面</h1>
</body>
</html>

unauthorized.html。当访问不够权限的页面时会跳转到该页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>unauthorized</title>
</head>
<body>
<h1>你未授权,请联系管理员</h1>
</body>
</html>

3.5、编写 shiro 的有关配置

新建一个config 包,添加以下文件

CustomRealm.java

/*** @Author: Zhiyu* @Date: 2021/7/13 10:40* @Description: 主要用于用户数据和shiro的交互工作*/
public class CustomRealm extends AuthorizingRealm {@AutowiredUserService userService;/*** 授权:给当前用户授权,以便能访问** @param principals* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {// principal 就是下面的方法 doGetAuthenticationInfo 中的return new SimpleAuthenticationInfo(user, user.getPassword(), "") 中的第一个参数 user 赋值的User principal = (User) principals.getPrimaryPrincipal();System.out.println("principal = " + principal);// 给资源进行授权SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 授权该用户的本身角色的权限info.addRole(principal.getRole().getName());return info;}/*** 认证:能不能登录等认证** @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("-------------进入了认证逻辑---------------");// token 中存储着 subject.login(token) 中传过来的数据UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();// 这里假设,数据库中的 username 字段是唯一字段,可以作为唯一标识,实际开发中可以适当修改,换汤不换药// 根据 username 去数据库查询用户信息// 数据库查询回来的数据User user = userService.queryByUsername(username);if (user == null) {// 用户名不存在// return null;  shiro 底层会抛出UnknowAccountExceptionthrow new UnknownAccountException();}// 第一个参数 user: 代表传值,及保存用户的信息,后面会用到// 第二个参数 填真正的密码,shiro 会帮我们做密码验证,无需我们自己做密码验证逻辑return new SimpleAuthenticationInfo(user, user.getPassword(), "");}
}

ShiroConfig.java

/*** @Author: Zhiyu* @Date: 2021/7/13 10:40* @Description: shiro 的配置* 完成下面三件事* 1.创建 ShiroFilterFactoryBean* 2.DefaultWebSecurityManager* 3.创建Realm并关联*/
@Configuration
public class ShiroConfig {@Bean(name = "customRealm")public CustomRealm customRealm() {return new CustomRealm();}@Bean(name = "securityManager")public SecurityManager securityManager(CustomRealm customRealm) {DefaultWebSecurityManager manager = new DefaultWebSecurityManager();manager.setRealm(customRealm);return manager;}/*** 过滤器配置** @param securityManager* @return*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);/***    Shiro内置过滤器,可以实现权限相关的拦截器*    常用的过滤器:*       anon: 无需认证(登录)可以访问*       authc: 必须认证才可以访问*       user: 如果使用rememberMe的功能可以直接访问*       perms: 该资源必须得到资源权限才可以访问*       roles: 该资源必须得到角色权限才可以访问*/// 1. 权限相关的拦截器(什么路径需要什么权限)LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();filterMap.put("/delete", "roles[root]"); //roles[root] 意思是访问/delete 需要角色 root// roles[admin,root]意思是访问/add 需要角色 admin或者root。// 如果不配置 RoleFilter,解决多角色and关系,则roles[admin,root]意思就是访问/add 需要 admin和root两个角色同时。filterMap.put("/add", "roles[admin,root]");// anon,意识是/test、/login / 无需认证(登录)可以访问filterMap.put("/test", "anon");filterMap.put("/login", "anon");filterMap.put("/", "anon");// authc 其余的访问都必须认证才可以访问,filterMap.put("/*", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);// 添加shiro 权限过滤器// 2. 配置自定义 or 角色 认证,把自定义过滤器配置进去即可LinkedHashMap<String, Filter> filters = new LinkedHashMap<>();filters.put("roles", new RoleFilter());shiroFilterFactoryBean.setFilters(filters);// 3. 修改默认的登录页面和未授权页面// 即访问需要登录有页面时会跳转到 /toLogin 请求// 即访问需要不够权限的时候页面时会跳转到 /toLogin 请求shiroFilterFactoryBean.setLoginUrl("/unauthorized");// 修改调整的登录页面shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");// 设置未授权提示页面return shiroFilterFactoryBean;}
}

RoleFilter.java

/*** @Author: Zhiyu* @Date: 2021/7/13 11:08* @Description: 重写Shiro自带角色权限过滤器* shiro自带的方法同一权限只能分配一个角色,默认所个角色的时候是 and 关系,不是 or 关系* 所以重写 重写Shiro自带角色权限过滤器 解决多角色 的时候是 or 关系*/
public class RoleFilter extends RolesAuthorizationFilter {@Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)throws IOException {final Subject subject = getSubject(request, response);final String[] rolesArray = (String[]) mappedValue;if (rolesArray == null || rolesArray.length == 0) {// 无指定角色时,无需检查,允许访问return true;}for (String roleName : rolesArray) {if (subject.hasRole(roleName)) {return true;}}return false;}
}

3.6、编写Controller层代码

新建一个controller包,添加 UserController.java 文件,内容如下

@Controller
public class UserController {/*** 使用 shiro 编写认证(登录)逻辑* 1. 获取 Subject* 2. 封装用户数据* 3. 执行登录方法*/@PostMapping("/login")public String login(String username, String password, Model model) {System.out.println("username = " + username);System.out.println("password = " + password);// 1.获取 SubjectSubject subject = SecurityUtils.getSubject();// 2. 封装用户数据UsernamePasswordToken token = new UsernamePasswordToken(username, password);String msg = "登录成功";try {// 3. 执行登录方法, 到 CustomRealm 类的doGetAuthenticationInfo中去执行认证逻辑subject.login(token);} catch (UnknownAccountException uae) {msg = "未知账户";} catch (IncorrectCredentialsException ice) {msg = "密码不正确";} catch (LockedAccountException lae) {msg = "账户已锁定";} catch (ExcessiveAttemptsException eae) {msg = "用户名或密码错误次数过多";} catch (AuthenticationException ae) {msg = "用户名或密码不正确!";}model.addAttribute("msg", msg);if (subject.isAuthenticated()) {// 登录成功,跳转到 index.htmlreturn "redirect:/index";} else {token.clear();return "login";}}
}

7、编写 WebMvcConfig, 配置无逻辑的访问页面跳转

在config 包下新建 WebMvcConfig.java ,代码如下

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {// 这里配置一些无逻辑处理的页面请求@Overridepublic void addViewControllers(ViewControllerRegistry registry) {/*** registry.addViewController("/add").setViewName("add");* 的意识等价于 在controller 层的*     @RequestMapping("/add")*     public String add() {*         return "add"; // 跳转到 add.html 页面*     }***  所以registry.addViewController("/add").setViewName("add");*  意思是:访问 /add 就会跳转到 add.html 页面*  下面的以此类推**/registry.addViewController("/add").setViewName("add");registry.addViewController("/delete").setViewName("delete");registry.addViewController("/query").setViewName("query");registry.addViewController("/toLogin").setViewName("login");registry.addViewController("/").setViewName("login");registry.addViewController("/unauthorized").setViewName("unauthorized");registry.addViewController("/index").setViewName("index");registry.addViewController("/test").setViewName("test");}
}

启动项目进行测试

4、测试

User 表数据如下

4.0、游客访问

游客直接在浏览器输入下面的地址

  • http://localhost:8080/add

  • http://localhost:8080/delete

  • http://localhost:8080/query

都是下面会跳转到登录页面

除了访问http://localhost:8080/test 可以正确跳转

4.1、测试无用户登录

访问 http://localhost:8080/, 输入如下信息

点击提交,然后显示的页面如下

4.2、测试密码不正确登录

访问 http://localhost:8080/, 输入如下信息

点击提交,然后显示的页面如下

4.3、测试 rootA用户正确登录

访问 http://localhost:8080/, 输入如下信息

点击提交,然后显示的页面如下

分别点击添加、删除、查询、测试页面,分别显示的页面如下

结果:可以看到全部页面都可以正常访问。

4.4、测试adminA用户正确登录

访问 http://localhost:8080/, 输入如下信息

点击提交,然后显示的页面如下

分别点击添加、删除、查询、测试页面,分别显示的页面如下

结果:拥有admin 角色的用户可以访问添加页面,查询页面、测试页面,除了删除页面不能访问

4.5、测试userA用户正确登录

访问 http://localhost:8080/, 输入如下信息

点击提交,然后显示的页面如下

分别点击添加、删除、查询、测试页面,分别显示的页面如下

结果:拥有 user 角色的用户可以访问 查询页面、测试页面,除了添加页面、删除页面不能访问

5、结语

  • 该项目不会将过多基础,直接实战,比较使用有一点基础的。
  • 该项目中没有使用密码加密,如果多人浏览并反馈需要,我可以再写篇密码加密认证的
  • 都是原创,希望看到这的能够点个赞支持一些。
  • 代码和数据库sql都放在github,链接如下:https://github.com/JiuRiYunYue/springboot-mybatis-shiro.git

一篇搞定 SpringBoot+Mybatis+Shiro 实现多角色权限管理相关推荐

  1. 3分钟搞定SpringBoot+Mybatis+druid多数据源和分布式事务

    在一些复杂的应用开发中,一个应用可能会涉及到连接多个数据源,所谓多数据源这里就定义为至少连接两个及以上的数据库了. 下面列举两种常用的场景: 一种是读写分离的数据源,例如一个读库和一个写库,读库负责各 ...

  2. SpringBoot的Web开发支持【超详细【一篇搞定】果断收藏系列】

    SpringBoot的Web开发支持 常用的服务器配置 使用Jetty服务器替换Tomcat 排除Tomcat的启动器,引入Jetty application.yml 编写入口程序 编写Control ...

  3. java 不重启部署_一篇文章带你搞定SpringBoot不重启项目实现修改静态资源

    一.通过配置文件控制静态资源的热部署 在配置文件 application.properties 中添加: #表示从这个默认不触发重启的目录中除去static目录 spring.devtools.res ...

  4. vlan配置实例详解_网工知识角|MUXVLAN技术详解,基本原理一篇搞定

    学网络,就在IE-LAB 国内高端网络工程师培养基地 MUX VLAN(Multiplex VLAN )提供了一种通过VLAN进行网络资源控制的机制.通过MUX VLAN提供的二层流量隔离的机制可以实 ...

  5. CentOS7搭建LNMP+WordPress一篇搞定

    零.关于本文 本文首次完成于2019年5月12日,经历多次修改.本文所有的参考文献,均以超链接的形式给出.考虑到网上的部分教程不够完整,有的已经过时,我将我搭建环境的方法记录下来. 这篇文章适合: 希 ...

  6. shiro、基于url权限管理、超详细

    如果需要本篇博客内容的代码!请到我的博客下载中心去下载   https://download.csdn.net/download/qq_36125138/10719559 项目运行图: 权限管理原理知 ...

  7. springboot整合security,mybatisPlus,thymeleaf实现登录认证及用户,菜单,角色权限管理

    介绍 本系统为springboot整合security,mybatisPlus,thymeleaf实现登录认证及用户,菜单,角色权限管理.页面为极简模式,没有任何渲染. 源码:https://gite ...

  8. SpringBoot+MyBatis+Shiro 搭建杂谈

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:用好Java中的枚举,真的没有那么简单!个人原创+1博客:点击前往,查看更多 链接:https://www.cn ...

  9. Linux常用命令大全,一篇搞定

    今日推荐 扔掉 Postman,一个工具全部搞定,真香!为啥查询那么慢?还在直接用JWT做鉴权?JJWT真香推荐 15 款常用开发工具干掉 navicat:这款 DB 管理工具才是y(永)y(远)d( ...

最新文章

  1. 计算机应用基础教材编写建议,【计算机应用论文】计算机应用基础校本教材编写研究(共3136字)...
  2. 正则匹配:Email 密码强度 身份证 手机号 日期 数字每4个字空一格等
  3. [内部项目]i前端如何增加一个页面
  4. 帮朋友配置的一台主机,配置发出来看看
  5. 【Emacs】Emacs for windows基本配置文件【转载】
  6. 《深度学习Python实践》第18章——持久化加载模型
  7. JavaScript的事件绑定及深入
  8. DELPHI基础教程 第二章 Delphi面向对象的编程方法
  9. GD32创建工程与启动文件选择
  10. hihocoder 1257 Snake Carpet
  11. 一张让android死机图片,导致安卓手机死机的照片拍摄者表示这张照片是无意之举...
  12. Linux内核设计与实现 第17章 设备与模块
  13. java查看内存信息
  14. Spacy分词php,spaCy 第二篇:语言模型
  15. 【游戏逆向】某某明月刀_技能冷却分析
  16. springboot自带的线程池ThreadPoolTaskExecutor、ThreadPoolTaskScheduler的深入应用——异步任务监听回调,任务中断案例
  17. 360手机官方刷机教程(N5系列通用)
  18. Android中复制到剪切板
  19. 【传感器sensor】机器人/无人驾驶常用传感器模型、选型与安装
  20. 大数据教程【05.01】--Python 数据分析简介

热门文章

  1. Jenkins使用FTP上传文件报错问题处理
  2. 微信公众号新变动!你都发现了吗?
  3. 时代变了,互联网与房产开发商能否找到真爱
  4. 【知识产权之专利权】论述题题库
  5. 升级IOS百度人脸SDK4.0采坑记录
  6. Command CompileAssetCatalog emitted errors but did not return a nonzero exit code to indicate failur
  7. 从TOP100summit看产品设计和运营创新的“B”计划和“C”计划
  8. JavaScript效率PK——统计特定字符在字符串中出现的次数
  9. route和bridge是什么意思_请问ROUTE 和 BRIDGE 是怎么分别的!
  10. 一起来学linux:磁盘与文件系统: