Shiro集成Spring
本篇博客主要讲述的是两者的集成。不涉及到各自的详细细节和功能。
因为官方给出的文档不够具体,对新手而言通过官方文档还不可以非常快的搭建出SpringShiro的webproject。本博客将通过实际的案例提供具体的教程。
案例分析:
项目名称:假期系统
组织机构:部门 > 小组
角色:Admin, SeniorManager,TeamLeader,Developer
资源:假期Leave
权限:申请Apply,审核Review, 复核ReReview。查看View
角色级别:Admin > Senior Manager >Team Leader > Developer
角色权限:
|
Admin |
Senior Manager |
Team Leader |
Developer |
Apply |
Y |
Y |
Y |
Y |
Review |
Y |
Y |
Y |
N |
ReReview |
Y |
Y |
N |
N |
View |
Y |
Y |
Y |
Y |
特殊需求:
1. 角色能够绑定到不同的组织机构级别,比方SeniorManager 是基于部门的,TeamLeader则是基于小组的
2. 角色的级别关系仅仅能在同样的部门中,不同部门之间的角色没有关联
3. 审核仅仅能是自己上级角色审核,复核必须是审核者的上级角色复核,即Developer提出的请假申请仅仅能TeamLeader来审核,而且由SeniorManager复核。
数据库设计
最简单的数据库设计例如以下:
表名 |
列名 |
描写叙述 |
类型 |
t_dept 部门表 |
id |
部门编号 |
Int |
name |
部门名称 |
Varchar |
|
|
|||
t_team 小组表 |
id |
小组编号 |
Int |
name |
小组名称 |
Varchar |
|
|
|||
t_user 用户表 |
id |
用户编号 |
Int |
username |
username称 |
Varchar |
|
password |
用户加密password |
Varchar |
|
salt |
用户加密盐 |
Varchar |
|
manager_id |
用户上级领导id |
Int |
|
|
|||
t_role 角色表 |
id |
角色编号 |
Int |
name |
角色名称 |
Varchar |
|
dept_flag |
角色是否关联部门 |
Bool |
|
team_flag |
角色是否关联小组 |
Bool |
|
|
|||
t_user_role 用户所属角色表 |
Id |
用户角色编号 |
Int |
user_id |
用户编号 |
Int |
|
dept_id |
部门编号 |
Int |
|
team_id |
小组编号 |
Int |
|
role_id |
角色编号 |
Int |
|
|
|||
t_resource 资源表 |
id |
资源编号 |
Int |
name |
资源名称 |
Varchar |
|
|
|||
t_permission 权限表 |
id |
权限编号 |
Int |
name |
权限名称 |
Varchar |
|
|
|||
t_role_resource_permission 角色拥有的资源权限表 |
id |
编号 |
Int |
role_id |
角色编号 |
Int |
|
resource_id |
资源编号 |
Int |
|
permission_id |
权限编号 |
Int |
|
|
|||
t_leave 请假申请表 |
id |
请假申请编号 |
Int |
user_id |
请假者编号 |
Int |
|
days |
请假时长 |
Int |
|
fromDate |
開始日期 |
Date |
|
toDate |
结束日期 |
Date |
|
remark |
请假说明 |
Varchar |
|
flag |
请假状态 |
Int |
|
apply_date |
申请的时间 |
Datetime |
|
review_user_id |
审核人编号 |
Int |
|
review_date |
审核日期 |
Date |
|
review_remark |
审核说明 |
Varchar |
|
rereview_user_id |
复核人编号 |
Int |
|
rereview_date |
复核日期 |
Date |
|
rereview_remark |
复核说明 |
Varchar |
加入測试数据:
项目搭建
Maven Project: pom.xml
新建一个maven项目,packaging设定为war,设定Spring和Shiro的版本号为3.1.4.RELEASE和1.2.3。并加入必要的依赖。
详细例如以下:
- <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.xx.shiro</groupId>
- <artifactId>demo</artifactId>
- <version>1.0.0</version>
- <packaging>war</packaging>
- <properties>
- <java-version>1.7</java-version>
- <org.springframework-version>3.1.4.RELEASE</org.springframework-version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <org.shiro-version>1.2.3</org.shiro-version>
- </properties>
- <dependencies>
- <!-- Java EE 6 API java enterprise edition -->
- <dependency>
- <groupId>javax</groupId>
- <artifactId>javaee-api</artifactId>
- <version>6.0</version>
- <scope>provided</scope>
- </dependency>
- <!-- spring-context [annotation...] -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${org.springframework-version}</version>
- <exclusions>
- <!-- Exclude Commons Logging in favor of SLF4j -->
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- spring modules start -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${org.springframework-version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>${org.springframework-version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>${org.springframework-version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aop</artifactId>
- <version>${org.springframework-version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-tx</artifactId>
- <version>${org.springframework-version}</version>
- </dependency>
- <!-- apache shiro start -->
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-core</artifactId>
- <version>${org.shiro-version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-ehcache</artifactId>
- <version>${org.shiro-version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-web</artifactId>
- <version>${org.shiro-version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-quartz</artifactId>
- <version>${org.shiro-version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>${org.shiro-version}</version>
- </dependency>
- <!-- apache shiro end -->
- <!-- jackson -->
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-core-asl</artifactId>
- <version>1.8.8</version>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-mapper-asl</artifactId>
- <version>1.8.8</version>
- </dependency>
- <!-- java.lang.* Extension -->
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
- <!-- java.io.InputStream and Reader Extension -->
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <!-- JavaServer Pages Standard Tag Library -->
- <dependency>
- <groupId>jstl</groupId>
- <artifactId>jstl</artifactId>
- <version>1.2</version>
- </dependency>
- <!-- slf4j -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.6.6</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.6.6</version>
- </dependency>
- <!-- log4j -->
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.15</version>
- <exclusions>
- <exclusion>
- <groupId>com.sun.jmx</groupId>
- <artifactId>jmxri</artifactId>
- </exclusion>
- <exclusion>
- <groupId>com.sun.jdmk</groupId>
- <artifactId>jmxtools</artifactId>
- </exclusion>
- <exclusion>
- <groupId>javax.jms</groupId>
- <artifactId>jms</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- encode -->
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.6</version>
- </dependency>
- <dependency>
- <groupId>com.xx.rtpc.shared.utils</groupId>
- <artifactId>rtpc-crypt</artifactId>
- <version>3.1.0</version>
- </dependency>
- <dependency>
- <groupId>c3p0</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.1</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.4</version>
- </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>2.2</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>demo</finalName>
- </build>
- </project>
配置web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- version="3.0"
- metadata-complete="false">
- <display-name>shiro-example</display-name>
- <!-- Spring配置文件開始 -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/dispatcher-servlet.xml
- </param-value>
- </context-param>
- <!-- listener -->
- <listener>
- <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
- </listener>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <!-- shiro 安全过滤器 -->
- <filter>
- <filter-name>shiroFilter</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- <async-supported>true</async-supported>
- <init-param>
- <param-name>targetFilterLifecycle</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>shiroFilter</filter-name>
- <url-pattern>/*</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- </filter-mapping>
- <servlet>
- <servlet-name>dispatcher</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dispatcher</servlet-name>
- <url-pattern>*.spring</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>/home.spring</welcome-file>
- </welcome-file-list>
- </web-app>
Spring Configure: dispatcher-servlet.xml
在src/main/webapp/WEB-INF以下新建Spring的配置文件。命名为dispatcher-servlet.xml.详细设定例如以下:
- <?xml version="1.0" encoding="UTF-8"?
- >
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
- <mvc:resources location="/resources/" mapping="/resources/**" />
- <context:component-scan base-package="com.xx.shiro.demo"></context:component-scan>
- <mvc:annotation-driven>
- <mvc:message-converters>
- <bean class="org.springframework.http.converter.StringHttpMessageConverter">
- <property name="supportedMediaTypes">
- <list>
- <value>text/html;charset=UTF-8</value>
- <value>text/plain;charset=UTF-8</value>
- </list>
- </property>
- </bean>
- <bean id="jsonHttpMessageConverter"
- class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
- <property name="supportedMediaTypes">
- <list>
- <value>application/json</value>
- <value>text/json</value>
- </list>
- </property>
- </bean>
- </mvc:message-converters>
- </mvc:annotation-driven>
- <!-- 凭证匹配器 -->
- <bean id="credentialsMatcher" class="com.xx.shiro.demo.credentials.DemoCredentialsMatcher">
- <property name="retry" value="3"/>
- <property name="hashAlgorithmName" value="md5"/>
- <property name="hashIterations" value="2"/>
- <property name="storedCredentialsHexEncoded" value="true"/>
- </bean>
- <!-- Realm实现 -->
- <bean id="xxDemoRealm" class="com.xx.shiro.demo.realm.XxDemoRealm">
- <property name="credentialsMatcher" ref="credentialsMatcher"/>
- <property name="userService" ref="userService" />
- </bean>
- <!-- 安全管理器 -->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="realm" ref="xxDemoRealm" />
- </bean>
- <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
- <bean
- class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
- <property name="staticMethod"
- value="org.apache.shiro.SecurityUtils.setSecurityManager" />
- <property name="arguments" ref="securityManager" />
- </bean>
- <!-- Shiro的Web过滤器 -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <property name="loginUrl" value="/login.spring" />
- <property name="successUrl" value="/home.spring" />
- <property name="filterChainDefinitions">
- <value>
- /login.sping = anon
- /resources/** = anon
- /** = user
- </value>
- </property>
- </bean>
- <!-- Shiro生命周期处理器 -->
- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
- <!-- Enable shiro annotations -->
- <bean
- class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
- depends-on="lifecycleBeanPostProcessor" />
- <bean
- class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
- <property name="securityManager" ref="securityManager" />
- </bean>
- <!-- 数据库连接 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver" />
- <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/shiro" />
- <property name="user" value="root" />
- <property name="password" value="admin" />
- <property name="maxPoolSize" value="100" />
- <property name="minPoolSize" value="10" />
- <property name="initialPoolSize" value="10" />
- <property name="maxIdleTime" value="1800" />
- <property name="acquireIncrement" value="10" />
- <property name="idleConnectionTestPeriod" value="600" />
- <property name="acquireRetryAttempts" value="30" />
- <property name="breakAfterAcquireFailure" value="false" />
- <property name="preferredTestQuery" value="SELECT 1" />
- </bean>
- <!-- User service and dao -->
- <bean id="userDao" class="com.xx.shiro.demo.dao.impl.UserDaoImpl">
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- <bean id="userService" class="com.xx.shiro.demo.service.impl.UserServiceImpl">
- <property name="userDao" ref="userDao" />
- </bean>
- <bean
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/pages/"></property>
- <property name="suffix" value=".jsp"></property>
- </bean>
- </beans>
从配置文件能够看出我们要实现两个重要的模块。一个是CredentialsMatcher, 另外一个叫做Realm。CredentialsMatcher是用来验证password的正确性,Realm则是来获取用户授权和认证的信息。
- <!-- 凭证匹配器 -->
- <bean id="credentialsMatcher" class="com.xx.shiro.demo.credentials.DemoCredentialsMatcher">
- <property name="retry" value="3"/>
- <property name="hashAlgorithmName" value="md5"/>
- <property name="hashIterations" value="2"/>
- <property name="storedCredentialsHexEncoded" value="true"/>
- </bean>
- <!-- Realm实现 -->
- <bean id="xxDemoRealm" class="com.xx.shiro.demo.realm.XxDemoRealm">
- <property name="credentialsMatcher" ref="credentialsMatcher"/>
- <property name="userService" ref="userService" />
- </bean>
首先来看一下自己定义的Realm,
它继承了抽象类AuthorizingRealm,同一时候AuthorizingRealm又继承了抽象类AuthenticatingRealm,所以自己定义的Realm中要实现两个抽象方法。一个是获取认证信息。另外一个是获取授权信息。详细例如以下:
- public class XxDemoRealm extends AuthorizingRealm {
- UserService userService;
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- if (principals == null) {
- throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
- }
- String username = (String)principals.getPrimaryPrincipal();
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- authorizationInfo.setRoles(userService.findRoles(username));
- authorizationInfo.setStringPermissions(userService.findPermissions(username));
- return authorizationInfo;
- }
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
- throws AuthenticationException {
- UsernamePasswordToken upToken = (UsernamePasswordToken) token;
- String username = upToken.getUsername();
- if (username == null) {
- throw new AccountException("Null usernames are not allowed by this realm.");
- }
- String[] pwdSalt = userService.getUserPasswordAndSalt(username);
- if (pwdSalt == null) {
- throw new AccountException("No account found for user [" + username + "]");
- }
- return new SimpleAuthenticationInfo(username, pwdSalt[0].toCharArray(),
- ByteSource.Util.bytes(username + pwdSalt[1]), getName());
- }
- public void setUserService(UserService userService) {
- this.userService = userService;
- }
- }
这里我们分别返回SimpleAuthenticationInfo和SimpleAuthorizationInfo。SimpleAuthenticationInfo是由username,登录password,password盐以及realm名称组成,而SimpleAuthorizationInfo继承与SimpleAuthenticationInfo。同一时候又包括了角色和权限的集合。
在spring的配置中我们定义自己定义realm的时候指定了凭证匹配器:
- <bean id="xxDemoRealm" class="com.xx.shiro.demo.realm.XxDemoRealm">
- <property name="credentialsMatcher" ref="credentialsMatcher"/>
- <property name="userService" ref="userService" />
- </bean>
凭证匹配器就是用来验证用户输入的帐号password和数据库中的password是否匹配。
- public class DemoCredentialsMatcher extends HashedCredentialsMatcher {
- // 这里应该用cache来做, 不要用Map
- private static Map<String, AtomicInteger> cache = new HashMap<String, AtomicInteger>();
- private int retry = 5;
- @Override
- public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
- String username = (String) token.getPrincipal();
- AtomicInteger retryCount = cache.get(username);
- if (retryCount == null) {
- retryCount = new AtomicInteger(0);
- cache.put(username, retryCount);
- }
- if (retryCount.incrementAndGet() > retry) {
- throw new ExcessiveAttemptsException();
- }
- boolean matches = super.doCredentialsMatch(token, info);
- if (matches) {
- cache.remove(username);
- }
- return matches;
- }
- public void setRetry(int retry) {
- this.retry = retry;
- }
- }
我们这里使用的是HashedCredentialsMatcher,另外加入了重试最大次数的机制。失败几次之后就不能登录了,解锁这里没有涉及到。
官方文档地址:http://shiro.apache.org/spring.html
未完待续。。
。。。
。
Shiro集成Spring的更多相关文章
- shiro集成spring&工作流程&DelegatingFilterProxy
1.集成Spring 参考文献: 新建web工程: ehcache-core来自Hibernate wen.xml <?xml version="1.0" encoding= ...
- shiro 集成spring 配置 学习记录(一)
首先当然是项目中需要增加shiro的架包依赖: <!-- shiro --> <dependency> <groupId>org.apache.shiro</ ...
- shiro 集成spring 使用 redis作为缓存 学习记录(六)
1.在applicationContext-redis.xml配置文件中增加如下: 申明一个cacheManager对象 用来注入到 shiro的 securityManager 属性 cac ...
- Shiro 集成Spring 使用 redis时 使用redisTemplate替代jedisPool(五)
1.添加依赖架包: <dependency> <groupId>org.springframework.data</groupId> <artifactId& ...
- shiro学习(四、shiro集成spring+springmvc)
依赖:spring-context,spring-MVC,shiro-core,shiro-spring,shiro-web 实话实说:web.xml,spring,springmvc配置文件好难 大 ...
- Apache Shiro 集成Spring(二)
1.依赖: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cor ...
- shiro与spring集成
简介 Apache Shiro 是 Java 的一个安全(权限)框架.主要提供了认证.授权.加密和会话管理等功能. Authentication:身份认证/登录,验证用户是不是拥有相应的身份:Auth ...
- shiro:集成Spring(四)
基于[加密及密码比对器(三)]项目改造 引入相关依赖环境 shiro-spring已经包含 shiro-core和shiro-web 所以这两个依赖可以删掉 <!--shiro继承spring依 ...
- cas+tomcat+shiro实现单点登录-4-Apache Shiro 集成Cas作为cas client端实现
目录 1.tomcat添加https安全协议 2.下载cas server端部署到tomcat上 3.CAS服务器深入配置(连接MYSQL) 4.Apache Shiro 集成Cas作为cas cli ...
随机推荐
- Python基础知识小结
1. 关于函数传参 def func(n, *args, **kwargs): print n print args print kwargs if __name__ == '__main__': # ...
- Android设计 - 图标设计概述(Iconography)
2014-10-30 张云飞VIR 翻译自:https://developer.android.com/design/style/iconography.html Iconography 图标设计概述 ...
- name是个特殊的变量名吗
这是为什么?求大神
- ES06--elasticsearch
ES06--elasticsearch unassigned错误解决(手动处理) 查看集群健康状态:curl -XGET http://localhost:9200/_cluster/health ...
- ubuntu14.04 3D桌面效果制作
参考:http://www.360doc.com/content/14/0919/22/11681374_410808557.shtml
- FreeRDP的安装配置(错误信息:SSL_read: Failure in SSL library (protocol error?))
最新文章:Virson's Blog 使用xfreerdp [serveripaddress]命令,连接xp/windows 2003都正常,但是在连接win7/2008时总是出错: ;------- ...
- ZARM in Linux & MIUI
zram是Linux内核的一个模块,之前被称为“compcache”.zram通过在RAM内的压缩快设备上分页,直到必须使用硬盘上的交换空间,以避免在磁盘上进行分页,从而提高性能.由于zram可以用内 ...
- 远程操作与端口转发 SSH原理与运用
SSH不仅可以用于远程主机登录,还可以直接在远程主机上执行操作. 上一节的操作,就是一个例子: $ ssh user@host 'mkdir -p .ssh && cat >&g ...
- VIM下的普通模式的相关知识
什么为一次操作? 从进行插入模式开始,直到返回普通模式为止,在此期间的任何修改都视为一次操作: 使用 u 可以撤销最新的修改: 所以呢,控制好在插入模式的操作就可以控制好撤销命令的粒度: 另外,最 ...
- Java如何获取正在运行的线程的Id?
在Java编程中,如何获取正在运行的线程的Id? 以下示例演示如何使用getThreadId()方法获取正在运行的线程的Id. package com.yiibai; public class IdT ...