2017.2.7 开涛shiro教程-第六章-Realm及相关对象(一)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398
根据下载的pdf学习。
第六章 Realm及相关对象
1.用户、角色、权限的关系
用户和角色是多对多,角色和权限也是多对多。
用户和权限通过角色建立关系。
角色是权限的集合。
(1)表准备
用户表:
角色表:
剩下的表类似,就不一一解释了。分别是权限表,用户-角色表,角色权限表。
(2)表对应的实体
2.环境准备
(1)pom.xml
3.Service和Dao层
(1)Service层
1 public interface PermissionService {
2 public Permission createPermission(Permission permission);
3 public void deletePermission(Long permissionId);
4 }
public interface RoleService {
public Role createRole(Role role);
public void deleteRole(Long roleId); /**
* 添加角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void correlationPermissions(Long roleId, Long... permissionIds); /**
* 移除角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void uncorrelationPermissions(Long roleId, Long... permissionIds); }
public interface UserService {
/**
* 创建用户
* @param user
*/
public User createUser(User user); /**
* 修改密码
* @param userId
* @param newPassword
*/
public void changePassword(Long userId, String newPassword); /**
* 添加用户-角色关系
* @param userId
* @param roleIds
*/
public void correlationRoles(Long userId, Long... roleIds); /**
* 移除用户-角色关系
* @param userId
* @param roleIds
*/
public void uncorrelationRoles(Long userId, Long... roleIds); /**
* 根据用户名查找用户
* @param username
* @return
*/
public User findByUsername(String username); /**
* 根据用户名查找其角色
* @param username
* @return
*/
public Set<String> findRoles(String username); /**
* 根据用户名查找其权限
* @param username
* @return
*/
public Set<String> findPermissions(String username); }
(2)Service实现层
public class PermissionServiceImpl implements PermissionService { private PermissionDao permissionDao = new PermissionDaoImpl(); public Permission createPermission(Permission permission) {
return permissionDao.createPermission(permission);
} public void deletePermission(Long permissionId) {
permissionDao.deletePermission(permissionId);
}
}
public class RoleServiceImpl implements RoleService { private RoleDao roleDao = new RoleDaoImpl(); public Role createRole(Role role) {
return roleDao.createRole(role);
} public void deleteRole(Long roleId) {
roleDao.deleteRole(roleId);
} /**
* 添加角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void correlationPermissions(Long roleId, Long... permissionIds) {
roleDao.correlationPermissions(roleId, permissionIds);
} /**
* 移除角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
roleDao.uncorrelationPermissions(roleId, permissionIds);
} }
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl();
private PasswordHelper passwordHelper = new PasswordHelper(); /**
* 创建用户
* @param user
*/
public User createUser(User user) {
//加密密码
passwordHelper.encryptPassword(user);
return userDao.createUser(user);
} /**
* 修改密码
* @param userId
* @param newPassword
*/
public void changePassword(Long userId, String newPassword) {
User user =userDao.findOne(userId);
user.setPassword(newPassword);
passwordHelper.encryptPassword(user);
userDao.updateUser(user);
} /**
* 添加用户-角色关系
* @param userId
* @param roleIds
*/
public void correlationRoles(Long userId, Long... roleIds) {
userDao.correlationRoles(userId, roleIds);
} /**
* 移除用户-角色关系
* @param userId
* @param roleIds
*/
public void uncorrelationRoles(Long userId, Long... roleIds) {
userDao.uncorrelationRoles(userId, roleIds);
} /**
* 根据用户名查找用户
* @param username
* @return
*/
public User findByUsername(String username) {
return userDao.findByUsername(username);
} /**
* 根据用户名查找其角色
* @param username
* @return
*/
public Set<String> findRoles(String username) {
return userDao.findRoles(username);
} /**
* 根据用户名查找其权限
* @param username
* @return
*/
public Set<String> findPermissions(String username) {
return userDao.findPermissions(username);
} }
import com.github.zhangkaitao.shiro.chapter6.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; public class PasswordHelper { private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator(); private String algorithmName = "md5";
private final int hashIterations = 2; public void encryptPassword(User user) { user.setSalt(randomNumberGenerator.nextBytes().toHex()); String newPassword = new SimpleHash(
algorithmName,
user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),
hashIterations).toHex(); user.setPassword(newPassword);
}
}
(3)Dao层
public interface PermissionDao {
public Permission createPermission(Permission permission);
public void deletePermission(Long permissionId);
}
public interface RoleDao { public Role createRole(Role role);
public void deleteRole(Long roleId); public void correlationPermissions(Long roleId, Long... permissionIds);
public void uncorrelationPermissions(Long roleId, Long... permissionIds); }
public interface UserDao { public User createUser(User user);
public void updateUser(User user);
public void deleteUser(Long userId); public void correlationRoles(Long userId, Long... roleIds);
public void uncorrelationRoles(Long userId, Long... roleIds); User findOne(Long userId);
User findByUsername(String username); Set<String> findRoles(String username);
Set<String> findPermissions(String username);
}
(4)dao实现层
import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
import com.github.zhangkaitao.shiro.chapter6.entity.Permission;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException; public class PermissionDaoImpl implements PermissionDao { private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate(); public Permission createPermission(final Permission permission) {
final String sql = "insert into sys_permissions(permission, description, available) values(?,?,?)"; GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement psst = connection.prepareStatement(sql, new String[] { "id" });
psst.setString(1, permission.getPermission());
psst.setString(2, permission.getDescription());
psst.setBoolean(3, permission.getAvailable());
return psst;
}
}, keyHolder);
permission.setId(keyHolder.getKey().longValue()); return permission;
} public void deletePermission(Long permissionId) {
//首先把与permission关联的相关表的数据删掉
String sql = "delete from sys_roles_permissions where permission_id=?";
jdbcTemplate.update(sql, permissionId); sql = "delete from sys_permissions where id=?";
jdbcTemplate.update(sql, permissionId);
} }
import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
import com.github.zhangkaitao.shiro.chapter6.entity.Role;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException; public class RoleDaoImpl implements RoleDao { private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate(); public Role createRole(final Role Role) {
final String sql = "insert into sys_roles(role, description, available) values(?,?,?)"; GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement psst = connection.prepareStatement(sql, new String[] { "id" });
psst.setString(1, Role.getRole());
psst.setString(2, Role.getDescription());
psst.setBoolean(3, Role.getAvailable());
return psst;
}
}, keyHolder);
Role.setId(keyHolder.getKey().longValue()); return Role;
} public void deleteRole(Long roleId) {
//首先把和role关联的相关表数据删掉
String sql = "delete from sys_users_roles where role_id=?";
jdbcTemplate.update(sql, roleId); sql = "delete from sys_roles where id=?";
jdbcTemplate.update(sql, roleId);
} @Override
public void correlationPermissions(Long roleId, Long... permissionIds) {
if(permissionIds == null || permissionIds.length == 0) {
return;
}
String sql = "insert into sys_roles_permissions(role_id, permission_id) values(?,?)";
for(Long permissionId : permissionIds) {
if(!exists(roleId, permissionId)) {
jdbcTemplate.update(sql, roleId, permissionId);
}
}
} @Override
public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
if(permissionIds == null || permissionIds.length == 0) {
return;
}
String sql = "delete from sys_roles_permissions where role_id=? and permission_id=?";
for(Long permissionId : permissionIds) {
if(exists(roleId, permissionId)) {
jdbcTemplate.update(sql, roleId, permissionId);
}
}
} private boolean exists(Long roleId, Long permissionId) {
String sql = "select count(1) from sys_roles_permissions where role_id=? and permission_id=?";
return jdbcTemplate.queryForObject(sql, Integer.class, roleId, permissionId) != 0;
} }
import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
import com.github.zhangkaitao.shiro.chapter6.entity.User;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set; public class UserDaoImpl implements UserDao { private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate(); public User createUser(final User user) {
final String sql = "insert into sys_users(username, password, salt, locked) values(?,?,?, ?)"; GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement psst = connection.prepareStatement(sql, new String[] { "id" });
psst.setString(1, user.getUsername());
psst.setString(2, user.getPassword());
psst.setString(3, user.getSalt());
psst.setBoolean(4, user.getLocked());
return psst;
}
}, keyHolder); user.setId(keyHolder.getKey().longValue());
return user;
} public void updateUser(User user) {
String sql = "update sys_users set username=?, password=?, salt=?, locked=? where id=?";
jdbcTemplate.update(sql, user.getUsername(), user.getPassword(), user.getSalt(), user.getLocked(), user.getId());
} public void deleteUser(Long userId) {
String sql = "delete from sys_users where id=?";
jdbcTemplate.update(sql, userId);
} @Override
public void correlationRoles(Long userId, Long... roleIds) {
if(roleIds == null || roleIds.length == 0) {
return;
}
String sql = "insert into sys_users_roles(user_id, role_id) values(?,?)";
for(Long roleId : roleIds) {
if(!exists(userId, roleId)) {
jdbcTemplate.update(sql, userId, roleId);
}
}
} @Override
public void uncorrelationRoles(Long userId, Long... roleIds) {
if(roleIds == null || roleIds.length == 0) {
return;
}
String sql = "delete from sys_users_roles where user_id=? and role_id=?";
for(Long roleId : roleIds) {
if(exists(userId, roleId)) {
jdbcTemplate.update(sql, userId, roleId);
}
}
} private boolean exists(Long userId, Long roleId) {
String sql = "select count(1) from sys_users_roles where user_id=? and role_id=?";
return jdbcTemplate.queryForObject(sql, Integer.class, userId, roleId) != 0;
} @Override
public User findOne(Long userId) {
String sql = "select id, username, password, salt, locked from sys_users where id=?";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), userId);
if(userList.size() == 0) {
return null;
}
return userList.get(0);
} @Override
public User findByUsername(String username) {
String sql = "select id, username, password, salt, locked from sys_users where username=?";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), username);
if(userList.size() == 0) {
return null;
}
return userList.get(0);
} @Override
public Set<String> findRoles(String username) {
String sql = "select role from sys_users u, sys_roles r,sys_users_roles ur where u.username=? and u.id=ur.user_id and r.id=ur.role_id";
return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
} @Override
public Set<String> findPermissions(String username) {
//TODO 此处可以优化,比如查询到role后,一起获取roleId,然后直接根据roleId获取即可
String sql = "select permission from sys_users u, sys_roles r, sys_permissions p, sys_users_roles ur, sys_roles_permissions rp where u.username=? and u.id=ur.user_id and r.id=ur.role_id and r.id=rp.role_id and p.id=rp.permission_id";
return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
}
}
4.Realm
(1)配置
(2)代码
import com.github.zhangkaitao.shiro.chapter6.service.UserService;
import com.github.zhangkaitao.shiro.chapter6.service.UserServiceImpl;
import com.github.zhangkaitao.shiro.chapter6.entity.User;
import org.apache.shiro.authc.*;
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; public class UserRealm extends AuthorizingRealm { private UserService userService = new UserServiceImpl(); @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//授权
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 {//认证
String username = (String)token.getPrincipal();
User user = userService.findByUsername(username); if(user == null) {
throw new UnknownAccountException();//没找到帐号
} if(Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); //帐号锁定
} //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
}
5.测试
包含这几种情况:登录成功、用户名错误、密码错误、密码超出重试次数、有/没有角色、有/没有权限的测试。
(1)测试基类
import com.github.zhangkaitao.shiro.chapter6.service.*;
import com.github.zhangkaitao.shiro.chapter6.entity.Permission;
import com.github.zhangkaitao.shiro.chapter6.entity.Role;
import com.github.zhangkaitao.shiro.chapter6.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.util.ThreadContext;
import org.junit.After;
import org.junit.Before; public abstract class BaseTest { protected PermissionService permissionService = new PermissionServiceImpl();
protected RoleService roleService = new RoleServiceImpl();
protected UserService userService = new UserServiceImpl(); protected String password = "123"; protected Permission p1;
protected Permission p2;
protected Permission p3;
protected Role r1;
protected Role r2;
protected User u1;
protected User u2;
protected User u3;
protected User u4; @Before
public void setUp() {
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_permissions");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users_roles");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles_permissions"); //1、新增权限
p1 = new Permission("user:create", "用户模块新增", Boolean.TRUE);
p2 = new Permission("user:update", "用户模块修改", Boolean.TRUE);
p3 = new Permission("menu:create", "菜单模块新增", Boolean.TRUE);
permissionService.createPermission(p1);
permissionService.createPermission(p2);
permissionService.createPermission(p3);
//2、新增角色
r1 = new Role("admin", "管理员", Boolean.TRUE);
r2 = new Role("user", "用户管理员", Boolean.TRUE);
roleService.createRole(r1);
roleService.createRole(r2);
//3、关联角色-权限
roleService.correlationPermissions(r1.getId(), p1.getId());
roleService.correlationPermissions(r1.getId(), p2.getId());
roleService.correlationPermissions(r1.getId(), p3.getId()); roleService.correlationPermissions(r2.getId(), p1.getId());
roleService.correlationPermissions(r2.getId(), p2.getId()); //4、新增用户
u1 = new User("zhang", password);
u2 = new User("li", password);
u3 = new User("wu", password);
u4 = new User("wang", password);
u4.setLocked(Boolean.TRUE);
userService.createUser(u1);
userService.createUser(u2);
userService.createUser(u3);
userService.createUser(u4);
//5、关联用户-角色
userService.correlationRoles(u1.getId(), r1.getId()); } @After
public void tearDown() throws Exception {
ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
} protected void login(String configFile, String username, String password) {
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory(configFile); //2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password); subject.login(token);
} public Subject subject() {
return SecurityUtils.getSubject();
} }
(2)测试类
import com.github.zhangkaitao.shiro.chapter6.BaseTest;
import junit.framework.Assert;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.junit.Test; public class UserRealmTest extends BaseTest { @Test
public void testLoginSuccess() {
login("classpath:shiro.ini", u1.getUsername(), password);
Assert.assertTrue(subject().isAuthenticated());
} @Test(expected = UnknownAccountException.class)
public void testLoginFailWithUnknownUsername() {
login("classpath:shiro.ini", u1.getUsername() + "1", password);
} @Test(expected = IncorrectCredentialsException.class)
public void testLoginFailWithErrorPassowrd() {
login("classpath:shiro.ini", u1.getUsername(), password + "1");
} @Test(expected = LockedAccountException.class)
public void testLoginFailWithLocked() {
login("classpath:shiro.ini", u4.getUsername(), password + "1");
} @Test(expected = ExcessiveAttemptsException.class)
public void testLoginFailWithLimitRetryCount() {
for(int i = 1; i <= 5; i++) {
try {
login("classpath:shiro.ini", u3.getUsername(), password + "1");
} catch (Exception e) {/*ignore*/}
}
login("classpath:shiro.ini", u3.getUsername(), password + "1"); //需要清空缓存,否则后续的执行就会遇到问题(或者使用一个全新账户测试)
} @Test
public void testHasRole() {
login("classpath:shiro.ini", u1.getUsername(), password );
Assert.assertTrue(subject().hasRole("admin"));
} @Test
public void testNoRole() {
login("classpath:shiro.ini", u2.getUsername(), password);
Assert.assertFalse(subject().hasRole("admin"));
} @Test
public void testHasPermission() {
login("classpath:shiro.ini", u1.getUsername(), password);
Assert.assertTrue(subject().isPermittedAll("user:create", "menu:create"));
} @Test
public void testNoPermission() {
login("classpath:shiro.ini", u2.getUsername(), password);
Assert.assertFalse(subject().isPermitted("user:create"));
} }
2017.2.7 开涛shiro教程-第六章-Realm及相关对象(一)的更多相关文章
- 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(四)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(四) 1.Subject的代码结构 ...
- 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(二)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(二) 1.Authenticatio ...
- 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(三)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(三) 1.准备3个Realm MyR ...
- 2017.2.16 开涛shiro教程-第十七章-OAuth2集成(一)服务器端
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十七章-OAuth2集成 1.OAuth2介 ...
- 2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(二) controller
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第二十一章-授予身份与切换身份(二) 1.回顾 ...
- 2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(一) table、entity、service、dao
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第二十一章 授予身份与切换身份(一) 1.使用场景 某个领导因为某 ...
- 2017.2.12 开涛shiro教程-第七章-与Web集成
2017.2.9 开涛shiro教程-第七章-与Web集成(一) 原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. ...
- 2017.2.16 开涛shiro教程-第十七章-OAuth2集成(二)客户端
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十七章-OAuth2集成 3.客户端 客户端 ...
- 2017.4.12 开涛shiro教程-第十八章-并发登录人数控制
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十八章-并发登录人数控制 shiro中没有提 ...
随机推荐
- Halcon17 windows 下载
Halcon17 windows 下载地址:http://www.211xun.com/download_page_9.html HALCON 17 是一套机器视觉图像处理库,由一千多个算子以及底层的 ...
- nyoj 题目14 会场安排问题
会场安排问题 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办.小刘的工 ...
- jquery复制当前tr行
//复制 var vBudgetCompileObj = (function() { /*table新增/移除行,参数:tableId*/ var getMaxIndex; var funGenera ...
- REDIS基础笔记
Redis基础笔记 资源链接 简介 简介 安装 五种数据类型及相应命令 1. 字符串类型 2. 散列类型 3. 列表类型 4. 集合类型 5. 有序集合 其他 事务 SORT 生存时间 任务队列 发布 ...
- [AHOI2014&&JSOI2014][bzoj3876] 支线剧情 [上下界费用流]
题面 传送门 思路 转化模型:给一张有向无环图,每次你可以选择一条路径走,花费的时间为路径上边权的总和,问要使所有边都被走至少一遍(可以重复),至少需要花费多久 走至少一遍,等价于覆盖这条边 也就是说 ...
- 【bzoj2400】Spoj 839 Optimal Marks 按位最大流
Spoj 839 Optimal Marks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 908 Solved: 347[Submit][Stat ...
- springboot 2.0配置集成thymeleaf的坑
Servlet.service() for servlet [dispatcherServlet] in context with path [] java.lang.NoClassDefFoundE ...
- js 如何刷新页面
Javascript刷新页面的几种方法(未测试):1 history.go(0)2 location.reload()3 location=location4 location.assign(loca ...
- BZOJ 3910: 火车
3910: 火车 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 358 Solved: 130[Submit][Status][Discuss] D ...
- 【HDOJ5555】Immortality of Frog(状压DP)
题意:给你一个NxN的网格,第N行的每一列都有个青蛙,这些青蛙只会往上走, 上帝会在每个膜中随机等概率放一个长生不老的药, 一共有N个膜,每个膜覆盖一些区间,如果这个区间恰好为N那么就是好膜,否则是坏 ...