SpringBoot&Shiro实现权限管理

引言

相信大家前来看这篇文章的时候,是有SpringBoot和Shiro基础的,所以本文只介绍整合的步骤,如果哪里写的不好,恳请大家能指出错误,谢谢!依赖以及一些配置文件请在源码里参考,请参见 https://github.com/Slags/springboot-learn/tree/master/1.springboot-shiro-authentication

个人博客:www.fqcoder.cn

一、数据库模板设计

在本文中,我们使用RBAC(Role-Based Access Control,基于角色的访问控制)模型设计用户,角色和权限间的关系。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。如下图所示:

然后我们在来根据这个模型图,设计数据库表,记得自己添加一点测试数据哦

CREATE TABLE `tb_permission`  (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact; CREATE TABLE `tb_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '角色名称',
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact; CREATE TABLE `tb_role_permission` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`permission_id` int(11) NOT NULL COMMENT '权限id'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact; CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`create_time` datetime(0) DEFAULT NULL,
`status` int(10) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact; CREATE TABLE `tb_user_role` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`user_id` int(11) NOT NULL COMMENT '用户id'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;

二、Pojo设计

我们创建对应的类,笔者这里用了lombok插件,记得先安装插件

@Data
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private Date createTime;
private Integer status;
} @Data
public class Role implements Serializable {
private Integer id;
private String name;
private String description;
} @Data
public class Permission implements Serializable {
private Integer id;
private String url;
private String name;
}

三、Dao层设计

因为我们只是做一个演示,只涉及到用户登录,用户角色、权限查找,并未实现过多方法

创建UserMapperRolePermissionMapperUserRoleMapper 三个接口

注意:记得在Mapper接口上面加一个扫描注解@Mapper或者在boot启动类上加一个@MapperScan(value = "mapper包路径")注解

public interface UserMapper {
@Select("select * from tb_user where username=#{username}")
User selectByName(String username);
}
-------------------------- public interface UserRoleMapper {
/**
*
* 查询用户角色(可能一个用户有多个角色)
* @param username
* @return
*/
@Select("select r.id,r.name,r.description from tb_role r " +
"left join tb_user_role ur on(r.id = ur.role_id)" +
"left join tb_user u on(u.id=ur.user_id)" +
"where u.username =#{username}")
List<Role> findByUserName(String username);
} ------------------------------------------------
public interface RolePermissionMapper {
/**
* 通过角色id查询权限
* @param roleId
* @return
*/
@Select("select p.id,p.url,p.name from tb_permission p " +
"left join tb_role_permission rp on(p.id=rp.permission_id)" +
"left join tb_role r on(r.id=rp.role_id)" +
"where r.id=#{roleId}")
List<Permission> findByRoleId(Integer roleId);
}

四、Shiro整合实现思路

好了,前面的一些东西,都是可以算是准备工作,现在才是真正开始整合Shiro了,我们先来屡一下思路,实现认证权限功能主要可以归纳为3点:

1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , SecurityManager为Shiro的安全管理器,管理着所有Subject;

2.在ShiroConfig中配置 ShiroFilterFactoryBean ,它是Shiro过滤器工厂类,依赖SecurityManager ;

3.自定义Realm实现类,包含 doGetAuthorizationInfo()doGetAuthenticationInfo()方法 ,

五、定义ShiroConfig配置类

/**
* @ClassName ShiroConfig
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:08
* @Version 1.0
*/
@Configuration
public class ShiroConfig { /**
* 这是shiro的大管家,相当于mybatis里的SqlSessionFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
//页面权限控制
shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroFilterMapFactory.shiroFilterMap());
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
} /**
* web应用管理配置
* @param shiroRealm
* @param cacheManager
* @param manager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(Realm shiroRealm, CacheManager cacheManager, RememberMeManager manager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setCacheManager(cacheManager);
securityManager.setRememberMeManager(manager);//记住Cookie
securityManager.setRealm(shiroRealm);
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* session过期控制
* @return
* @author fuce
* @Date 2019年11月2日 下午12:49:49
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
// 设置session过期时间3600s
Long timeout=60L*1000*60;//毫秒级别
defaultWebSessionManager.setGlobalSessionTimeout(timeout);
return defaultWebSessionManager;
}
/**
* 加密算法
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");//采用MD5 进行加密
hashedCredentialsMatcher.setHashIterations(1);//加密次数
return hashedCredentialsMatcher;
} /**
* 记住我的配置
* @return
*/
@Bean
public RememberMeManager rememberMeManager() {
Cookie cookie = new SimpleCookie("rememberMe");
cookie.setHttpOnly(true);//通过js脚本将无法读取到cookie信息
cookie.setMaxAge(60 * 60 * 24);//cookie保存一天
CookieRememberMeManager manager=new CookieRememberMeManager();
manager.setCookie(cookie);
return manager;
}
/**
* 缓存配置
* @return
*/
@Bean
public CacheManager cacheManager() {
MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();//使用内存缓存
return cacheManager;
} /**
* 配置realm,用于认证和授权
* @param hashedCredentialsMatcher
* @return
*/
@Bean
public AuthorizingRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
MyShiroRealm shiroRealm = new MyShiroRealm();
//校验密码用到的算法
// shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return shiroRealm;
} /**
* 启用shiro方言,这样能在页面上使用shiro标签
* @return
*/
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
} /**
* 启用shiro注解
*加入注解的使用,不加入这个注解不生效
*/
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
} @Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
} }

注意:(当时笔者遇到的一个小问题,贴出来给大家涨姿势)

注解无效,登录时不会执行验证角色和权限的方法,只会执行登录验证方法,遂查询资料,得知shiro在subject.login(token)方法时不会执行doGetAuthorizationInfo方法,只有在访问到有权限验证的接口时会调用查看权限,于是猜想注解无效,发现shiro的权限注解需要开启才能有用,添加在配置文件中加入advisorAutoProxyCreatorgetAuthorizationAttributeSourceAdvisor两个bean开启shiro注解,解决问题。

六.创建ShiroFilterMapFactory类

注意:

1.这里要用LinkedHashMap 保证有序

2.filterChain基于短路机制,即最先匹配原则,

3.像anon、authc等都是Shiro为我们实现的过滤器,我给出了一张表,在文章尾附录,自行查看

/**
* @ClassName ShiroFilterMapFactory
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:09
* @Version 1.0
*/
public class ShiroFilterMapFactory { public static Map<String, String> shiroFilterMap() {
// 设置路径映射,注意这里要用LinkedHashMap 保证有序
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//对所有用户认证
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
//对所有页面进行认证
filterChainDefinitionMap.put("/**", "authc");
return filterChainDefinitionMap;
}
}

配置完了ShiroConfig后,实现自己的Realm,然后注入到SecurityManager里

七、实现自定义Realm类

自定义Realm类需要继承 AuthorizingRealm 类,实现 doGetAuthorizationInfo()和doGetAuthenticationInfo()方法即可 ,

doGetAuthorizationInfo() 方法是进行授权的方法,获取角色的权限信息

doGetAuthenticationInfo()方法是进行用户认证的方法,验证用户名和密码

/**
* @ClassName MyShiroRealm
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:08
* @Version 1.0
*/
@Service
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Autowired
private UserRoleMapper userRoleMapper;
@Autowired
private RolePermissionMapper rolePermissionMapper; /**
* 获取用户角色和权限
* @param principal
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
if(principal == null){
throw new AuthorizationException("principals should not be null");
}
User userInfo= (User) SecurityUtils.getSubject().getPrincipal();
System.out.println("用户-->"+userInfo.getUsername()+"获取权限中");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //用户获取角色集
List<Role> roleList=userRoleMapper.findByUserName(userInfo.getUsername());
Set<String> roleSet=new HashSet<>();
for (Role r:roleList){
Integer roleId=r.getId();//获取角色id
simpleAuthorizationInfo.addRole(r.getName());//添加角色名字
List<Permission> permissionList=rolePermissionMapper.findByRoleId(roleId);
for (Permission p:permissionList){
//添加权限
simpleAuthorizationInfo.addStringPermission(p.getName());
}
} System.out.println("角色为-> " + simpleAuthorizationInfo.getRoles());
System.out.println("权限为-> " + simpleAuthorizationInfo.getStringPermissions());
return simpleAuthorizationInfo;
} /**
* 登录认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取用户输入的用户名密码
String username= (String) token.getPrincipal();
String password=new String((char[])token.getCredentials()); System.out.println("用户输入--->username:"+username+"-->password:"+password); //在数据库中查询
User userInfo=userMapper.selectByName(username);
if (userInfo == null) {
throw new UnknownAccountException("用户名或密码错误!");
}
if (!password.equals(userInfo.getPassword())) {
throw new IncorrectCredentialsException("用户名或密码错误!");
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, // 用户名
userInfo.getPassword(), // 密码
getName() // realm name
);
return authenticationInfo;
}
}

其中UnknownAccountException等异常为Shiro自带异常,Shiro具有丰富的运行时AuthenticationException层次结构,可以准确指出尝试失败的原因。

八、控制层设计

1.创建一个LoginController.class类

用来处理登录访问请求

/**
* @ClassName LoginController
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 6:06
* @Version 1.0
*/
@Controller
public class LoginController { @GetMapping("/login")
public String login(){
return "login";
} @GetMapping("/")
public String home(){
return "redirect:/index";
} @GetMapping("/index")
public String index(Model model){
User user= (User) SecurityUtils.getSubject().getPrincipal();
model.addAttribute("user",user);
return "index";
} @PostMapping("login")
@ResponseBody
public AjaxResult login(User user,Boolean rememberMe){
System.out.println("user = " + user);
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
//获取Subject 对象
Subject subject= SecurityUtils.getSubject();
try {
if (rememberMe){
token.setRememberMe(true);
}
subject.login(token);
return AjaxResult.success("/index");
} catch (UnknownAccountException e) {
return AjaxResult.error(e.getMessage());
} catch (IncorrectCredentialsException e) {
return AjaxResult.error(e.getMessage());
}
}
@GetMapping("/403")
public String forbid(){
return "403";
}
}

2.创建一个UserController.class类

用于处理User类的访问请求,并使用Shiro权限注解控制权限:

/**
* @ClassName UserController
* @Description TODO
* @Author fqCoder
* @Date 2020/3/3 15:14
* @Version 1.0
*/
@RestController
@RequestMapping("/user")
public class UserController { @RequiresPermissions("user:queryAll")
@GetMapping("/queryAll")
public String queryAll(){ //只演示框架...功能不实现
return "查询列表";
} @RequiresPermissions("user:add")
@GetMapping("/add")
public String userAdd(){
return "添加用户";
} @RequiresPermissions("user:delete")
@GetMapping("/delete")
public String userDelete(){
return "删除用户";
}
}

九、前端页面设计

1.编写login.html页面

这里我只贴重要代码,具体的代码,到这里找哦!

<form id="loginForm">
<input type="text" id="username" name="username" class="text" />
<input type="password" id="password" name="password" />
</form>
<div class="signin">
<input id="loginBut" type="button" value="Login" >
</div> -------js代码----
<script type="text/javascript">
$.fn.serializeObject = function () {
var o = {};
var a = this.serializeArray();
$.each(a, function () {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value);
} else {
o[this.name] = this.value || '';
}
});
return o;
}; $(function () {
$("#loginBut").click(function () {
var arr=$('#loginForm').serializeObject();
$.ajax({
url: '/login',
type: 'post',
data: arr,
dataType: "json",
success: function (data) {
if (data.code==200){
location.href=data.msg;
} else {
alert(data.msg);
}
},
error: function (data) {
alert(data.msg);
}
})
});
});
</script>

当用户登录进来的时候调到index.html

2.编写index.html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>番茄欢迎您!</h1>
登录用户:【[[${user.username}]]】
<a th:href="@{/logout}">注销</a> <h2>权限测试</h2>
<a th:href="@{/user/queryAll}">获取用户全部信息</a>
<a th:href="@{/user/add}">添加用户</a>
<a th:href="@{/user/delete}">删除用户</a>
</body>
</html>

3.编写403页面

比较简单,此处能用就行

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>403</title>
</head>
<body>
<h1>403权限不够</h1>
<a href="/index">首页</a>
</body>
</html>

十、测试&问题

启动项目:访问http://localhost:8080/,它会自动拦截,页面重定向到 http://localhost:8080/login ,登录成功跳转到http://localhost:8080/index

问题:

登录测试用户的时候,访问没有权限的链接请求时,后台抛出org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method异常

当时以为在ShiroConfig配置类中配置了shiroFilterFactoryBean.setUnauthorizedUrl("/403");

没有权限的请求会自动从定向到/403,然后却是抛出了异常,后来在一篇文章中看到了,说这个设置只对filterChain起作用 ,针对这个问题,我们可以定义一个全局异常捕获类:

@ControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {
@ExceptionHandler(value = AuthorizationException.class)
public String handleAuthorizationException() {
return "403";
}
}

然后再启动项目,登录测试账号,访问没有权限的请求,页面成功定向到/403

源码链接: https://github.com/Slags/springboot-learn/tree/master/1.springboot-shiro-authentication

至此,笔者刚开始写,不是写的很好,欢迎各位网友踊跃指出不足,谢谢!

附录:

1.Shiro拦截机制表

Filter Name Class Description
anon org.apache.shiro.web.filter.authc.AnonymousFilter 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例/static/**=anon
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter 基于表单的拦截器;如/**=authc,如果没有登录会跳到相应的登录页面登录
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter Basic HTTP身份验证拦截器
logout org.apache.shiro.web.filter.authc.LogoutFilter 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/),示例/logout=logout
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter 不创建会话拦截器,调用subject.getSession(false)不会有什么问题,但是如果subject.getSession(true)将抛出DisabledSessionException异常
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例/user/**=perms["user:create"]
port org.apache.shiro.web.filter.authz.PortFilter 端口拦截器,主要属性port(80):可以通过的端口;示例/test= port[80],如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter rest风格拦截器,自动根据请求方法构建权限字符串;示例/users=rest[user],会自动拼出user:read,user:create,user:update,user:delete权限字符串进行权限匹配(所有都得匹配,isPermittedAll)
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 角色授权拦截器,验证用户是否拥有所有角色;示例/admin/**=roles[admin]
ssl org.apache.shiro.web.filter.authz.SslFilter SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口443;其他和port拦截器一样;
user org.apache.shiro.web.filter.authc.UserFilter 用户拦截器,用户已经身份验证/记住我登录的都可;示例/**=user

SpringBoot&Shiro实现权限管理的更多相关文章

  1. spring-boot-plus集成Shiro+JWT权限管理

    SpringBoot+Shiro+JWT权限管理 Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. 使用Shiro的易于理解的API,您可以 ...

  2. SpringBoot与Shiro整合权限管理实战

    SpringBoot与Shiro整合权限管理实战 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] *观看本文章需要有一定SpringBoot整合经验* Shiro框架简介 Apach ...

  3. 【shiro】(5)---基于Shiro的权限管理

    基于Shiro的权限管理项目搭建 前面写了四篇有关权限的文章,算是这篇文章的铺垫了.这篇文章采用 开发环境           JDK1.8          Eclipse          Mav ...

  4. springBoot2.0 配置shiro实现权限管理

    一.前言 基于上一篇springBoot2.0 配置 mybatis+mybatisPlus+redis 这一篇加入shiro实现权限管理 二.shiro介绍 2.1 功能特点 Shiro 包含 10 ...

  5. Dubbo学习系列之九(Shiro+JWT权限管理)

    村长让小王给村里各系统来一套SSO方案做整合,隔壁的陈家村流行使用Session+认证中心方法,但小王想尝试点新鲜的,于是想到了JWT方案,那JWT是啥呢?JavaWebToken简称JWT,就是一个 ...

  6. SpringBoot搭建基于Apache Shiro的权限管理功能

    Shiro 是什么 Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 ...

  7. spring boot 2 + shiro 实现权限管理

    Shiro是一个功能强大且易于使用的Java安全框架,主要功能有身份验证.授权.加密和会话管理.看了网上一些文章,下面2篇文章写得不错.Springboot2.0 集成shiro权限管理 Spring ...

  8. 使用shiro做权限管理的学习笔记整理

    Shiro权限管理 参考:https://www.cnblogs.com/jpfss/p/8352031.html Shiro解决的问题 授权和鉴别的问题:Authenrization(授权) Aut ...

  9. springboot + shiro 构建权限模块

    权限模块基本流程 权限模块的基本流程:用户申请账号和权限 -->登陆认证 -->安全管控模块认证 -->调用具体权限模块(基于角色的权限控制) --> 登陆成功 -->访 ...

随机推荐

  1. 序列化模块ModelSerializer

    课程准备 配置:settings.py INSTALLED_APPS = [ # ... 'rest_framework', ] DATABASES = { 'default': { 'ENGINE' ...

  2. C++ sizeof 运算符

    sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeof 的语法如下: ...

  3. How Cocoa Beans Grow And Are Harvested Into Chocolate

    What is Cocoa Beans Do you like chocolate? Most people do. The smooth, brown candy is deliciously sw ...

  4. addEventListener和onclick的区别

    onclick只出现一次alert:我是click2[很正常第一次click事件会被第二次所覆盖],但是addEventListener却可以先后运行,不会被覆盖[正如:它允许给一个事件注册多个监听器 ...

  5. linux的nohup命令的用法(后台运行程序命令)

    linux的nohup命令的用法. 在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台: /usr/ ...

  6. spring创建bean异常

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappi ...

  7. linux下如何查看服务器的硬件配置信息

    性能测试时一定要确定测试环境和的硬件配置.软件版本配置,保证和线上一致,才更接近真实环境. 那么linux下如何查看服务器的硬件配置信息?? 一.查看cpu信息 1.所有信息 lscpu [root@ ...

  8. org.apache.http.NoHttpResponseException

    org.apache.http.NoHttpResponseException 异常: org.apache.http.NoHttpResponseException: The target serv ...

  9. [LC] 142. Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To r ...

  10. Eclipse 配置Android 开发环境

    1.eclipse安装ADT插件. 地址:http://dl-ssl.google.com/android/eclipse/ 2.安装成功后,提示重启.重新启动后弹出android sdk 的路径选择 ...