数据库

先准备数据库啦。

 1 DROP DATABASE IF EXISTS shiro;
 2 CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
 3 USE shiro;
 4
 5 drop table if exists user;
 6 drop table if exists role;
 7 drop table if exists permission;
 8 drop table if exists user_role;
 9 drop table if exists role_permission;
10
11 create table user (
12   id bigint auto_increment,
13   name varchar(100),
14   password varchar(100),
15   salt varchar(100),
16   constraint pk_users primary key(id)
17 ) charset=utf8 ENGINE=InnoDB;
18
19 create table role (
20   id bigint auto_increment,
21   name varchar(100),
22   desc_ varchar(100),
23   constraint pk_roles primary key(id)
24 ) charset=utf8 ENGINE=InnoDB;
25
26 create table permission (
27   id bigint auto_increment,
28   name varchar(100),
29   desc_ varchar(100),
30   url varchar(100),
31   constraint pk_permissions primary key(id)
32 ) charset=utf8 ENGINE=InnoDB;
33
34 create table user_role (
35   id bigint auto_increment,
36   uid bigint,
37   rid bigint,
38   constraint pk_users_roles primary key(id)
39 ) charset=utf8 ENGINE=InnoDB;
40
41 create table role_permission (
42   id bigint auto_increment,
43   rid bigint,
44   pid bigint,
45   constraint pk_roles_permissions primary key(id)
46 ) charset=utf8 ENGINE=InnoDB;
47
48 INSERT INTO `permission` VALUES (1,'addProduct','增加产品','/addProduct');
49 INSERT INTO `permission` VALUES (2,'deleteProduct','删除产品','/deleteProduct');
50 INSERT INTO `permission` VALUES (3,'editeProduct','编辑产品','/editeProduct');
51 INSERT INTO `permission` VALUES (4,'updateProduct','修改产品','/updateProduct');
52 INSERT INTO `permission` VALUES (5,'listProduct','查看产品','/listProduct');
53 INSERT INTO `permission` VALUES (6,'addOrder','增加订单','/addOrder');
54 INSERT INTO `permission` VALUES (7,'deleteOrder','删除订单','/deleteOrder');
55 INSERT INTO `permission` VALUES (8,'editeOrder','编辑订单','/editeOrder');
56 INSERT INTO `permission` VALUES (9,'updateOrder','修改订单','/updateOrder');
57 INSERT INTO `permission` VALUES (10,'listOrder','查看订单','/listOrder');
58 INSERT INTO `role` VALUES (1,'admin','超级管理员');
59 INSERT INTO `role` VALUES (2,'productManager','产品管理员');
60 INSERT INTO `role` VALUES (3,'orderManager','订单管理员');
61 INSERT INTO `role_permission` VALUES (1,1,1);
62 INSERT INTO `role_permission` VALUES (2,1,2);
63 INSERT INTO `role_permission` VALUES (3,1,3);
64 INSERT INTO `role_permission` VALUES (4,1,4);
65 INSERT INTO `role_permission` VALUES (5,1,5);
66 INSERT INTO `role_permission` VALUES (6,1,6);
67 INSERT INTO `role_permission` VALUES (7,1,7);
68 INSERT INTO `role_permission` VALUES (8,1,8);
69 INSERT INTO `role_permission` VALUES (9,1,9);
70 INSERT INTO `role_permission` VALUES (10,1,10);
71 INSERT INTO `role_permission` VALUES (11,2,1);
72 INSERT INTO `role_permission` VALUES (12,2,2);
73 INSERT INTO `role_permission` VALUES (13,2,3);
74 INSERT INTO `role_permission` VALUES (14,2,4);
75 INSERT INTO `role_permission` VALUES (15,2,5);
76 INSERT INTO `role_permission` VALUES (50,3,10);
77 INSERT INTO `role_permission` VALUES (51,3,9);
78 INSERT INTO `role_permission` VALUES (52,3,8);
79 INSERT INTO `role_permission` VALUES (53,3,7);
80 INSERT INTO `role_permission` VALUES (54,3,6);
81 INSERT INTO `role_permission` VALUES (55,3,1);
82 INSERT INTO `role_permission` VALUES (56,5,11);
83 INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg==');
84 INSERT INTO `user` VALUES (2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
85 INSERT INTO `user_role` VALUES (43,2,2);
86 INSERT INTO `user_role` VALUES (45,1,1);

点击展开

基于前面的知识点继续进行

下面只展示基于前面的代码做修改

PageController.java

首先是PageController.java 里原本通过注解方式的@RequiresPermissions和@RequiresRoles 注释掉了

 1 package com.how2java.controller;
 2
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.RequestMethod;
 6
 7 //专门用于显示页面的控制器
 8 @Controller
 9 @RequestMapping("")
10 public class PageController {
11
12     @RequestMapping("index")
13     public String index(){
14         return "index";
15     }
16
17 //  @RequiresPermissions("deleteOrder")
18     @RequestMapping("deleteOrder")
19     public String deleteOrder(){
20         return "deleteOrder";
21     }
22 //  @RequiresRoles("productManager")
23     @RequestMapping("deleteProduct")
24     public String deleteProduct(){
25         return "deleteProduct";
26     }
27     @RequestMapping("listProduct")
28     public String listProduct(){
29         return "listProduct";
30     }
31
32     @RequestMapping(value="/login",method=RequestMethod.GET)
33     public String login(){
34         return "login";
35     }
36     @RequestMapping("unauthorized")
37     public String noPerms(){
38         return "unauthorized";
39     }
40
41 }

点击展开

PermissionService.java

增加了两个方法 needInterceptor,listPermissionURLs

 1 package com.how2java.service;
 2
 3 import java.util.List;
 4 import java.util.Set;
 5
 6 import com.how2java.pojo.Permission;
 7 import com.how2java.pojo.Role;
 8
 9 public interface PermissionService {
10     public Set<String> listPermissions(String userName);
11
12     public List<Permission> list();
13
14     public void add(Permission permission);
15
16     public void delete(Long id);
17
18     public Permission get(Long id);
19
20     public void update(Permission permission);
21
22     public List<Permission> list(Role role);
23
24     public boolean needInterceptor(String requestURI);
25
26     public Set<String> listPermissionURLs(String userName);
27
28 }

点击展开

PermissionServiceImpl.java

为两个方法 needInterceptor,listPermissionURLs 增加了实现
needInterceptor 表示是否要进行拦截,判断依据是如果访问的某个url,在权限系统里存在,就要进行拦截。 如果不存在,就放行了。
这一种策略,也可以切换成另一个,即,访问的地址如果不存在于权限系统中,就提示没有拦截。 这两种做法没有对错之分,取决于业务上希望如何制定权限策略。

listPermissionURLs(User user) 用来获取某个用户所拥有的权限地址集合

  1 package com.how2java.service.impl;
  2
  3 import java.util.ArrayList;
  4 import java.util.HashSet;
  5 import java.util.List;
  6 import java.util.Set;
  7
  8 import org.springframework.beans.factory.annotation.Autowired;
  9 import org.springframework.stereotype.Service;
 10
 11 import com.how2java.mapper.PermissionMapper;
 12 import com.how2java.mapper.RolePermissionMapper;
 13 import com.how2java.pojo.Permission;
 14 import com.how2java.pojo.PermissionExample;
 15 import com.how2java.pojo.Role;
 16 import com.how2java.pojo.RolePermission;
 17 import com.how2java.pojo.RolePermissionExample;
 18 import com.how2java.service.PermissionService;
 19 import com.how2java.service.RoleService;
 20 import com.how2java.service.UserService;
 21
 22 @Service
 23 public class PermissionServiceImpl implements PermissionService {
 24
 25     @Autowired
 26     PermissionMapper permissionMapper;
 27     @Autowired
 28     UserService userService;
 29     @Autowired
 30     RoleService roleService;
 31     @Autowired
 32     RolePermissionMapper rolePermissionMapper;
 33
 34     @Override
 35     public Set<String> listPermissions(String userName) {
 36         Set<String> result = new HashSet<>();
 37         List<Role> roles = roleService.listRoles(userName);
 38
 39         List<RolePermission> rolePermissions = new ArrayList<>();
 40
 41         for (Role role : roles) {
 42             RolePermissionExample example = new RolePermissionExample();
 43             example.createCriteria().andRidEqualTo(role.getId());
 44             List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
 45             rolePermissions.addAll(rps);
 46         }
 47
 48         for (RolePermission rolePermission : rolePermissions) {
 49             Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
 50             result.add(p.getName());
 51         }
 52
 53         return result;
 54     }
 55
 56     @Override
 57     public void add(Permission u) {
 58         permissionMapper.insert(u);
 59     }
 60
 61     @Override
 62     public void delete(Long id) {
 63         permissionMapper.deleteByPrimaryKey(id);
 64     }
 65
 66     @Override
 67     public void update(Permission u) {
 68         permissionMapper.updateByPrimaryKeySelective(u);
 69     }
 70
 71     @Override
 72     public Permission get(Long id) {
 73         return permissionMapper.selectByPrimaryKey(id);
 74     }
 75
 76     @Override
 77     public List<Permission> list() {
 78         PermissionExample example = new PermissionExample();
 79         example.setOrderByClause("id desc");
 80         return permissionMapper.selectByExample(example);
 81
 82     }
 83
 84     @Override
 85     public List<Permission> list(Role role) {
 86         List<Permission> result = new ArrayList<>();
 87         RolePermissionExample example = new RolePermissionExample();
 88         example.createCriteria().andRidEqualTo(role.getId());
 89         List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
 90         for (RolePermission rolePermission : rps) {
 91             result.add(permissionMapper.selectByPrimaryKey(rolePermission.getPid()));
 92         }
 93
 94         return result;
 95     }
 96
 97     @Override
 98     public boolean needInterceptor(String requestURI) {
 99         List<Permission> ps = list();
100         for (Permission p : ps) {
101             if (p.getUrl().equals(requestURI))
102                 return true;
103         }
104         return false;
105     }
106
107     @Override
108     public Set<String> listPermissionURLs(String userName) {
109         Set<String> result = new HashSet<>();
110         List<Role> roles = roleService.listRoles(userName);
111
112         List<RolePermission> rolePermissions = new ArrayList<>();
113
114         for (Role role : roles) {
115             RolePermissionExample example = new RolePermissionExample();
116             example.createCriteria().andRidEqualTo(role.getId());
117             List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
118             rolePermissions.addAll(rps);
119         }
120
121         for (RolePermission rolePermission : rolePermissions) {
122             Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
123             result.add(p.getUrl());
124         }
125
126         return result;
127     }
128
129 }

点击展开

URLPathMatchingFilter.java

PathMatchingFilter 是shiro 内置过滤器 PathMatchingFilter 继承了这个它。
基本思路如下:
1. 如果没登录就跳转到登录
2. 如果当前访问路径没有在权限系统里维护,则允许访问
3. 当前用户所拥有的权限如何不包含当前的访问地址,则跳转到/unauthorized,否则就允许访问

 1 package com.how2java.filter;
 2
 3 import java.util.Set;
 4
 5 import javax.servlet.ServletRequest;
 6 import javax.servlet.ServletResponse;
 7
 8 import org.apache.shiro.SecurityUtils;
 9 import org.apache.shiro.authz.UnauthorizedException;
10 import org.apache.shiro.subject.Subject;
11 import org.apache.shiro.web.filter.PathMatchingFilter;
12 import org.apache.shiro.web.util.WebUtils;
13 import org.springframework.beans.factory.annotation.Autowired;
14
15 import com.how2java.service.PermissionService;
16
17 public class URLPathMatchingFilter extends PathMatchingFilter {
18     @Autowired
19     PermissionService permissionService;
20
21     @Override
22     protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
23             throws Exception {
24         String requestURI = getPathWithinApplication(request);
25
26         System.out.println("requestURI:" + requestURI);
27
28         Subject subject = SecurityUtils.getSubject();
29         // 如果没有登录,就跳转到登录页面
30         if (!subject.isAuthenticated()) {
31             WebUtils.issueRedirect(request, response, "/login");
32             return false;
33         }
34
35         // 看看这个路径权限里有没有维护,如果没有维护,一律放行(也可以改为一律不放行)
36         boolean needInterceptor = permissionService.needInterceptor(requestURI);
37         if (!needInterceptor) {
38             return true;
39         } else {
40             boolean hasPermission = false;
41             String userName = subject.getPrincipal().toString();
42             Set<String> permissionUrls = permissionService.listPermissionURLs(userName);
43             for (String url : permissionUrls) {
44                 // 这就表示当前用户有这个权限
45                 if (url.equals(requestURI)) {
46                     hasPermission = true;
47                     break;
48                 }
49             }
50
51             if (hasPermission)
52                 return true;
53             else {
54                 UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURI + " 的权限");
55
56                 subject.getSession().setAttribute("ex", ex);
57
58                 WebUtils.issueRedirect(request, response, "/unauthorized");
59                 return false;
60             }
61
62         }
63
64     }
65 }

点击展开

applicationContext-shiro.xml

首先声明URLPathMatchingFilter 过滤器

<bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/>

在shiro中使用这个过滤器

<entry key="url" value-ref="urlPathMatchingFilter" />

过滤规则是所有访问

/** = url

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3     xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
  4     xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
  5     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
  6     xmlns:aop="http://www.springframework.org/schema/aop"
  7     xsi:schemaLocation="http://www.springframework.org/schema/beans
  8     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx
  9     http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context
 10     http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc
 11     http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop
 12     http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util
 13     http://www.springframework.org/schema/util/spring-util.xsd">
 14
 15     <!-- url过滤器 -->
 16     <bean id="urlPathMatchingFilter" class="com.how2java.filter.URLPathMatchingFilter"/>
 17
 18     <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
 19     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 20         <!-- 调用我们配置的权限管理器 -->
 21         <property name="securityManager" ref="securityManager" />
 22         <!-- 配置我们的登录请求地址 -->
 23         <property name="loginUrl" value="/login" />
 24         <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 -->
 25         <property name="unauthorizedUrl" value="/unauthorized" />
 26         <!-- 退出 -->
 27         <property name="filters">
 28             <util:map>
 29                 <entry key="logout" value-ref="logoutFilter" />
 30                 <entry key="url" value-ref="urlPathMatchingFilter" />
 31             </util:map>
 32         </property>
 33         <!-- 权限配置 -->
 34         <property name="filterChainDefinitions">
 35             <value>
 36                 <!-- anon表示此地址不需要任何权限即可访问 -->
 37                 /login=anon
 38                 /index=anon
 39                 /static/**=anon
 40                 <!-- 只对业务功能进行权限管理,权限配置本身不需要没有做权限要求,这样做是为了不让初学者混淆 -->
 41                 /config/**=anon
 42                 /doLogout=logout
 43                 <!--所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过过滤器url -->
 44                 /** = url
 45             </value>
 46         </property>
 47     </bean>
 48     <!-- 退出过滤器 -->
 49     <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
 50         <property name="redirectUrl" value="/index" />
 51     </bean>
 52
 53     <!-- 会话ID生成器 -->
 54     <bean id="sessionIdGenerator"
 55         class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
 56     <!-- 会话Cookie模板 关闭浏览器立即失效 -->
 57     <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
 58         <constructor-arg value="sid" />
 59         <property name="httpOnly" value="true" />
 60         <property name="maxAge" value="-1" />
 61     </bean>
 62     <!-- 会话DAO -->
 63     <bean id="sessionDAO"
 64         class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
 65         <property name="sessionIdGenerator" ref="sessionIdGenerator" />
 66     </bean>
 67     <!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 -->
 68     <bean name="sessionValidationScheduler"
 69         class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
 70         <property name="interval" value="1800000" />
 71         <property name="sessionManager" ref="sessionManager" />
 72     </bean>
 73     <!-- 会话管理器 -->
 74     <bean id="sessionManager"
 75         class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
 76         <!-- 全局会话超时时间(单位毫秒),默认30分钟 -->
 77         <property name="globalSessionTimeout" value="1800000" />
 78         <property name="deleteInvalidSessions" value="true" />
 79         <property name="sessionValidationSchedulerEnabled" value="true" />
 80         <property name="sessionValidationScheduler" ref="sessionValidationScheduler" />
 81         <property name="sessionDAO" ref="sessionDAO" />
 82         <property name="sessionIdCookieEnabled" value="true" />
 83         <property name="sessionIdCookie" ref="sessionIdCookie" />
 84     </bean>
 85
 86     <!-- 安全管理器 -->
 87     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 88         <property name="realm" ref="databaseRealm" />
 89         <property name="sessionManager" ref="sessionManager" />
 90     </bean>
 91     <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
 92     <bean
 93         class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
 94         <property name="staticMethod"
 95             value="org.apache.shiro.SecurityUtils.setSecurityManager" />
 96         <property name="arguments" ref="securityManager" />
 97     </bean>
 98
 99     <!-- 密码匹配器 -->
100     <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
101         <property name="hashAlgorithmName" value="md5"/>
102         <property name="hashIterations" value="2"/>
103         <property name="storedCredentialsHexEncoded" value="true"/>
104     </bean>
105
106     <bean id="databaseRealm" class="com.how2java.realm.DatabaseRealm">
107         <property name="credentialsMatcher" ref="credentialsMatcher"/>
108     </bean>
109
110     <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
111     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
112 </beans>

点击展开

jsp 们

jsp前端页面这里就不贴了。先要的到下面下载。

关于角色

在本知识点中,权限通过url进行灵活配置了。 但是角色还没有和url对应起来。 为什么不把角色也对应起来呢?
从代码开发的角度讲是可以做的,无非就是在 role表上增加一个url 字段。 但是从权限管理本身的角度看,当一个url 既对应权限表的数据,又对应角色表的数据,反而容易产生混淆。
反倒是现在这种,url地址,仅仅和权限表关联起来,在逻辑上明晰简单,也更容易维护。 所以就放弃了角色表也进行url维护的做法了。

结束

大家可以跑起来试一下。

代码下载地址:https://gitee.com/fengyuduke/my_open_resources/blob/master/shiro-url.zip

另外:项目所需jar包下载地址 https://gitee.com/fengyuduke/my_open_resources/tree/jarPackage/

转载于:https://www.cnblogs.com/fengyuduke/p/10496019.html

Apache Shiro(六)-基于URL配置权限相关推荐

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

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

  2. Apache Shiro的运行流程和权限控制方式分析

    Apache Shiro的运行流程和权限控制方式分析 Shiro的架构有3个主要的概念: Subject SecurityManager Realms 下面的关系图是关于这些组件是如何交互的高级概述. ...

  3. 基于URL的权限验证流程总结

    之前写过一篇博客:拦截器实现基于Url的权限管理,文章中讲解了怎么用拦截器实现url权限认证,这仅仅是权限管理的一部分.今天这篇博客就来说说一个项目完整的权限认证流程. 1. 准备权限数据 服务器启动 ...

  4. Spring 整合 Apache Shiro 实现各等级的权限管理

    Spring 整合 Apache Shiro 实现各等级的权限管理 2015-10-25 JAVA, SECURITY, SHIRO, SPRING Background 前几个月在做一个常规的权限隔 ...

  5. Apache Shiro入门

    Apache Shiro入门 @(Shiro)[shiro,安全框架] Apache Shiro入门 Apache Shiro基本概述 Apache Shiro基本概念 使用Shiro能做什么 Shi ...

  6. apache shiro内置过滤器 标签 注解

    内置过滤器 anon(匿名)  org.apache.shiro.web.filter.authc.AnonymousFilter authc(身份验证)       org.apache.shiro ...

  7. Apache Shiro 认证绕过漏洞(CVE-2020-1957)

    文章目录 漏洞描述(介绍.成因) 漏洞危害 适用场景 实验环境 漏洞复现过程 1. 开启docker环境 2. 构造url绕过验证 URL请求过程 修复建议 漏洞描述(介绍.成因) 使用 Apache ...

  8. 【Shiro权限管理】5. Shiro权限URL 配置细节

    上一次总结中重点讲解了Shiro的配置,其中一个过滤请求并管理权限的重要配置为shiroFilter,样例配置如下所示: <bean id="shiroFilter" cla ...

  9. shiro教程(1)-基于url权限管理

    一. 权限管理 1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自 ...

  10. Apache shiro 权限

    2021SC@SDUSC 文档目录 Apache shiro学习文档 第一章 Apache Shiro 概述 第二章 Apache Shiro 架构 第三章 Apache Shiro 配置 3.1 配 ...

最新文章

  1. 学习笔记TF065:TensorFlowOnSpark
  2. “好的软件人员一生必看的六十本书”
  3. easyUI menu动态添加
  4. CCNA题库关于Frame-relay看图答题的解答
  5. rsa java ao_RSA加解密工具类
  6. pythonweb框架
  7. redis和memcache的对比
  8. 以下会使线程进入到阻塞状态的是_Python并行编程(五):多线程同步之event(事件)...
  9. LIRe 源代码分析 3:基本接口(ImageSearcher)
  10. Windows10 adb安装与环境变量配置
  11. DOS原理和常用命令详解示例
  12. chr 13 java 替换_【转】ASCII码对应表chr(9)、chr(10)、chr(13)、chr(32)、chr(34)、chr(39)...
  13. 简单聊一聊如今火爆当下的数字孪生技术到底为何物
  14. 李沐-斯坦福《实用机器学习》-01章
  15. 三菱FX5U系列PLC内置模拟量使用方法和输入输出信号接线
  16. SecureCRT 入门使用
  17. 灰度图像的频率域滤波——理想低通滤波器(Matlab)
  18. PCB设计入门总结!建议收藏!
  19. 资源网站合集 五个值得你收藏的网站
  20. Flutter Sliver大家族之SliverPersistentHeader()和SliverToBoxAdapter()组件(实现固定头布局)③

热门文章

  1. Error information: “Error: SignerSign() failed.“ (-2147012889/0x80072ee7)
  2. 主板找不到SSD解决一例
  3. 高级插座的过载保护是否真的可靠?
  4. LINUX下载编译libyuv
  5. 一句代码错误,就要出差
  6. FREETYPE旋转功能初探
  7. 全网首发:解决办法:shmget()一直失败,errno=-22
  8. linux卸载rpm安装的golang,linux下go安装/卸载重装-Go语言中文社区
  9. redis windows切割日志文件_开发者笔记:Windows下搭建简易单机Redis集群测试环境...
  10. win2012 定时自动备份mysql_SQL SERVER 2012数据库自动备份的方法