网站推荐、资源下载等 | 个人网站

springboot与redis

该项目已上传至GitHub:https://github.com/xiaostudy/springboot_redis

 

用到的框架技术有:springboot、mybatis、shiro、redis

前端有:layui、jqGrid

 

这里先不讲redis在Windows安装,比较简单,百度看一下其他文章就可以了,有空这里也可以补一个教程。

 

1、先看项目目录

 

2、下面放源码

实体类,权限PermissionEntity.java

 1 package com.xiaostudy.shiro_test1.entity;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6  * 权限实体类
 7  * Created with IntelliJ IDEA.
 8  * User: Administrator
 9  * Date: 2019/6/8
10  * Time: 14:21
11  * Description: No Description
12  */
13 public class PermissionEntity implements Serializable {
14     private String id;
15     private String name;
16     private String url;
17 
18     public String getId() {
19         return id;
20     }
21 
22     public void setId(String id) {
23         this.id = id;
24     }
25 
26     public String getName() {
27         return name;
28     }
29 
30     public void setName(String name) {
31         this.name = name;
32     }
33 
34     public String getUrl() {
35         return url;
36     }
37 
38     public void setUrl(String url) {
39         this.url = url;
40     }
41 }

 

实体类,角色RoleEntity.java

 1 package com.xiaostudy.shiro_test1.entity;
 2 
 3 import java.io.Serializable;
 4 import java.util.HashSet;
 5 import java.util.Set;
 6 
 7 /**
 8  * 角色实体类
 9  * Created with IntelliJ IDEA.
10  * User: Administrator
11  * Date: 2019/6/8
12  * Time: 14:24
13  * Description: No Description
14  */
15 public class RoleEntity implements Serializable {
16     private String id;
17     private String name;
18     private Set<PermissionEntity> permissions = new HashSet<>();
19 
20     public String getId() {
21         return id;
22     }
23 
24     public void setId(String id) {
25         this.id = id;
26     }
27 
28     public String getName() {
29         return name;
30     }
31 
32     public void setName(String name) {
33         this.name = name;
34     }
35 
36     public Set<PermissionEntity> getPermissions() {
37         return permissions;
38     }
39 
40     public void setPermissions(Set<PermissionEntity> permissions) {
41         this.permissions = permissions;
42     }
43 }

 

实体类,用户UserEntity.java

 1 package com.xiaostudy.shiro_test1.entity;
 2 
 3 import java.io.Serializable;
 4 import java.util.HashSet;
 5 import java.util.Set;
 6 
 7 /**
 8  * 用户实体类
 9  * Created with IntelliJ IDEA.
10  * User: Administrator
11  * Date: 2019/6/8
12  * Time: 14:26
13  * Description: No Description
14  */
15 public class UserEntity implements Serializable {
16     private String id;
17     private String name;
18     private String password;
19     private Set<RoleEntity> roles = new HashSet<>();
20 
21     public String getId() {
22         return id;
23     }
24 
25     public void setId(String id) {
26         this.id = id;
27     }
28 
29     public String getName() {
30         return name;
31     }
32 
33     public void setName(String name) {
34         this.name = name;
35     }
36 
37     public String getPassword() {
38         return password;
39     }
40 
41     public void setPassword(String password) {
42         this.password = password;
43     }
44 
45     public Set<RoleEntity> getRoles() {
46         return roles;
47     }
48 
49     public void setRoles(Set<RoleEntity> roles) {
50         this.roles = roles;
51     }
52 }

 

实体类,测试redis实体类TestRedisEntity.java

 1 package com.xiaostudy.shiro_test1.entity;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6  * Created with IntelliJ IDEA.
 7  * User: Administrator
 8  * Date: 2019/6/8
 9  * Time: 22:04
10  * Description: No Description
11  */
12 public class TestRedisEntity implements Serializable {
13     private int id;
14     private String name;
15     private String password;
16 
17     public int getId() {
18         return id;
19     }
20 
21     public void setId(int id) {
22         this.id = id;
23     }
24 
25     public String getName() {
26         return name;
27     }
28 
29     public void setName(String name) {
30         this.name = name;
31     }
32 
33     public String getPassword() {
34         return password;
35     }
36 
37     public void setPassword(String password) {
38         this.password = password;
39     }
40 }

 

自定义Realm类,UserRealm.java

 1 package com.xiaostudy.shiro_test1.realm;
 2 
 3 import com.xiaostudy.shiro_test1.entity.PermissionEntity;
 4 import com.xiaostudy.shiro_test1.entity.RoleEntity;
 5 import com.xiaostudy.shiro_test1.entity.UserEntity;
 6 import com.xiaostudy.shiro_test1.service.UserService;
 7 import org.apache.shiro.SecurityUtils;
 8 import org.apache.shiro.authc.*;
 9 import org.apache.shiro.authz.AuthorizationInfo;
10 import org.apache.shiro.authz.SimpleAuthorizationInfo;
11 import org.apache.shiro.realm.AuthorizingRealm;
12 import org.apache.shiro.subject.PrincipalCollection;
13 import org.apache.shiro.subject.Subject;
14 import org.apache.shiro.util.ByteSource;
15 import org.springframework.beans.factory.annotation.Autowired;
16 
17 import java.util.Collection;
18 import java.util.HashSet;
19 import java.util.Set;
20 
21 /**
22  * 自定义Realm,实现授权与认证
23  * Created with IntelliJ IDEA.
24  * User: Administrator
25  * Date: 2019/6/8
26  * Time: 15:01
27  * Description: No Description
28  */
29 public class UserRealm extends AuthorizingRealm {
30 
31     @Autowired
32     private UserService userService;
33 
34     /**
35      * 用户授权
36      **/
37     @Override
38     protected AuthorizationInfo doGetAuthorizationInfo(
39             PrincipalCollection principalCollection) {
40 
41         System.out.println("===执行授权===");
42 
43         Subject subject = SecurityUtils.getSubject();
44         UserEntity user = (UserEntity)subject.getPrincipal();
45         if(user != null){
46             SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
47             // 角色字符串集合
48             Collection<String> rolesCollection = new HashSet<>();
49             // 权限字符串集合
50             Collection<String> premissionCollection = new HashSet<>();
51             // 读取并赋值用户角色与权限
52             Set<RoleEntity> roles = user.getRoles();
53             for(RoleEntity role : roles){
54                 rolesCollection.add(role.getName());
55                 Set<PermissionEntity> permissions = role.getPermissions();
56                 for (PermissionEntity permission : permissions){
57                     // 权限名称为PermissionEntity为字段url
58                     premissionCollection.add(permission.getUrl());
59                 }
60                 info.addStringPermissions(premissionCollection);
61             }
62             info.addRoles(rolesCollection);
63             return info;
64         }
65         return null;
66     }
67 
68     /**
69      * 用户认证
70      **/
71     @Override
72     protected AuthenticationInfo doGetAuthenticationInfo(
73             AuthenticationToken authenticationToken) throws AuthenticationException {
74 
75         System.out.println("===执行认证===");
76 
77         UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
78         UserEntity bean = userService.findByName(token.getUsername());
79 
80         if(bean == null){
81             // 用户不存在
82             throw new UnknownAccountException();
83         } else {
84             bean = userService.findById(bean.getId());
85             if(null == bean) {
86                 // 认证失败
87                 throw new AuthenticationException();
88             }
89         }
90 
91         ByteSource credentialsSalt = ByteSource.Util.bytes(bean.getName());
92 
93         return new SimpleAuthenticationInfo(bean, bean.getPassword(),
94                 credentialsSalt, getName());
95     }
96 }

 

处理没权限异常,NoPermissionException.java

 1 package com.xiaostudy.shiro_test1.exception;
 2 
 3 import org.apache.shiro.authz.AuthorizationException;
 4 import org.apache.shiro.authz.UnauthorizedException;
 5 import org.springframework.stereotype.Component;
 6 import org.springframework.web.bind.annotation.ControllerAdvice;
 7 import org.springframework.web.bind.annotation.ExceptionHandler;
 8 import org.springframework.web.bind.annotation.ResponseBody;
 9 
10 /**
11  * Created with IntelliJ IDEA.
12  * User: Administrator
13  * Date: 2019/6/8
14  * Time: 15:13
15  * Description: No Description
16  */
17 @ControllerAdvice
18 public class NoPermissionException {
19     // 授权失败,就是说没有该权限
20     @ExceptionHandler(UnauthorizedException.class)
21     public String handleShiroException(Exception ex) {
22         return "/error/unAuth";
23     }
24 
25     @ResponseBody
26     @ExceptionHandler(AuthorizationException.class)
27     public String AuthorizationException(Exception ex) {
28         return "权限认证失败";
29     }
30 }

 

shiro配置类,ShiroConfig.java

  1 package com.xiaostudy.shiro_test1.config;
  2 
  3 import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
  4 import com.xiaostudy.shiro_test1.realm.UserRealm;
  5 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  6 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  7 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  8 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  9 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 10 import org.springframework.context.annotation.Bean;
 11 import org.springframework.context.annotation.Configuration;
 12 
 13 import java.util.HashMap;
 14 import java.util.LinkedHashMap;
 15 import java.util.Map;
 16 
 17 /**
 18  * Shiro配置类
 19  * Created with IntelliJ IDEA.
 20  * User: Administrator
 21  * Date: 2019/6/8
 22  * Time: 15:06
 23  * Description: No Description
 24  */
 25 @Configuration
 26 public class ShiroConfig {
 27 
 28     // 创建自定义 realm
 29     @Bean
 30     public UserRealm userRealm() {
 31         UserRealm userRealm = new UserRealm();
 32         return userRealm;
 33     }
 34 
 35     // 创建 SecurityManager 对象
 36     @Bean
 37     public DefaultWebSecurityManager securityManager() {
 38         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
 39         securityManager.setRealm(userRealm());
 40         return securityManager;
 41     }
 42 
 43     // Filter工厂,设置对应的过滤条件和跳转条件
 44     @Bean
 45     public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
 46         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
 47         shiroFilterFactoryBean.setSecurityManager(securityManager);
 48         /**
 49          * anon:匿名用户可访问
 50          * authc:认证用户可访问
 51          * user:使用rememberMe可访问
 52          * perms:对应权限可访问
 53          * role:对应角色权限可访问
 54          */
 55         LinkedHashMap<String, String> map = new LinkedHashMap<>();
 56 //        map.put("/resources/**", "anon");//匿名访问静态资源
 57         map.put("/static/**", "anon");//匿名访问静态资源
 58         map.put("/statics/**", "anon");//匿名访问静态资源
 59         map.put("/jquery.jqGrid-4.6.0/**", "anon");//匿名访问静态资源
 60         map.put("/jquery-ui-1.12.0-rc.2/**", "anon");//匿名访问静态资源
 61         map.put("/layui/**", "anon");//匿名访问静态资源
 62         map.put("/external/**", "anon");//匿名访问静态资源
 63         map.put("/jquery/**", "anon");//匿名访问静态资源
 64         map.put("/js/**", "anon");//匿名访问静态资源
 65         map.put("/css/**", "anon");//匿名访问静态资源
 66         map.put("/images/**", "anon");//匿名访问静态资源
 67         // 开放登录接口
 68         map.put("/login", "anon");
 69 //        map.put("/login", "authc");
 70         // 对登录跳转接口进行释放
 71         map.put("/error", "anon");
 72         // 对所有用户认证
 73         map.put("/**", "authc");
 74         // 登出
 75         map.put("/logout", "logout");
 76         // 登录
 77         // 注意:这里配置的 /login 是指到 @RequestMapping(value="/login")中的 /login
 78         shiroFilterFactoryBean.setLoginUrl("/login");
 79         // 首页
 80         shiroFilterFactoryBean.setSuccessUrl("/index");
 81         // 错误页面,认证不通过跳转
 82         shiroFilterFactoryBean.setUnauthorizedUrl("/error/unAuth");
 83         shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
 84         return shiroFilterFactoryBean;
 85     }
 86 
 87     // 加入注解的使用,不加这个,注解不生效
 88     @Bean
 89     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
 90         AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
 91         authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
 92         return authorizationAttributeSourceAdvisor;
 93     }
 94 
 95     // 跟上面的注解配置搭配使用,有时候加了上面的配置后注解不生效,需要加入下面的配置
 96     @Bean
 97     @ConditionalOnMissingBean
 98     public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
 99         DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
100         app.setProxyTargetClass(true);
101         return app;
102     }
103 
104     @Bean
105     public ShiroDialect shiroDialect() {
106         return new ShiroDialect();
107     }
108 }

 

静态资源过滤配置类【告诉shiro不要拦截】,WebMvcConfig.java

 

 1 package com.xiaostudy.shiro_test1.config;
 2 
 3 import org.springframework.context.annotation.Configuration;
 4 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 6 
 7 /**
 8  * Created with IntelliJ IDEA.
 9  * User: Administrator
10  * Date: 2019/6/9
11  * Time: 0:51
12  * Description: No Description
13  */
14 @Configuration
15 public class WebMvcConfig implements WebMvcConfigurer {
16 
17     /**
18      * @author xiaobu
19      * @date 2019/1/18 13:51
20      * @param registry  registry
21      * @descprition  等价于 http://localhost:9001/1.txt 依次在static upload目录下找1.txt文件
22      * @version 1.0
23      */
24     @Override
25     public void addResourceHandlers(ResourceHandlerRegistry registry) {
26         registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
27         registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
28     }
29 
30 }

 

用户mapper,UserMapper.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 3 <mapper namespace="com.xiaostudy.shiro_test1.mapper.UserMapper">
 4 
 5     <resultMap id="userMap" type="com.xiaostudy.shiro_test1.entity.UserEntity">
 6         <id property="id" column="id"/>
 7         <result property="name" column="name"/>
 8         <result property="password" column="password"/>
 9         <collection property="roles" ofType="com.xiaostudy.shiro_test1.entity.RoleEntity">
10             <id property="id" column="roleId"/>
11             <result property="name" column="roleName"/>
12             <collection property="permissions" ofType="com.xiaostudy.shiro_test1.entity.PermissionEntity">
13                 <id property="id" column="permissionId"/>
14                 <result property="name" column="permissionName"/>
15                 <result property="url" column="permissionUrl"/>
16             </collection>
17         </collection>
18     </resultMap>
19 
20     <select id="findByName" parameterType="java.lang.String" resultType="com.xiaostudy.shiro_test1.entity.UserEntity">
21       SELECT id, name, password
22         FROM user
23           WHERE name = #{name}
24     </select>
25 
26     <select id="findById" parameterType="java.lang.String" resultMap="userMap">
27       SELECT user.id, user.name, user.password,
28             role.id as roleId, role.name as roleName,
29             permission.id as permissionId,
30             permission.name as permissionName,
31             permission.url as permissionUrl
32         FROM user, user_role, role, role_permission, permission
33           WHERE user.id = #{id}
34             AND user.id = user_role.user_id
35             AND user_role.role_id = role.id
36             AND role.id = role_permission.role_id
37             AND role_permission.permission_id = permission.id
38     </select>
39 
40 </mapper>

 

测试redis的mapper,TestRedisMapper.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 3 <mapper namespace="com.xiaostudy.shiro_test1.mapper.TestRedisMapper">
 4 
 5     <select id="selectAll" resultType="com.xiaostudy.shiro_test1.entity.TestRedisEntity" >
 6       SELECT id, name, password
 7         FROM test_redis;
 8     </select>
 9 
10     <select id="selectPages" parameterType="java.lang.Integer" resultType="com.xiaostudy.shiro_test1.entity.TestRedisEntity" >
11       SELECT id, name, password
12         FROM test_redis limit #{page}, #{rows};
13     </select>
14 
15     <select id="selectTotal" resultType="java.lang.Integer" >
16       SELECT COUNT(*) as total FROM test_redis;
17     </select>
18 
19     <select id="selectById" parameterType="java.lang.Integer" resultType="com.xiaostudy.shiro_test1.entity.TestRedisEntity">
20       SELECT id, name, password
21         FROM test_redis
22           WHERE id = #{id};
23     </select>
24 
25     <select id="selectByName" parameterType="java.lang.String" resultType="com.xiaostudy.shiro_test1.entity.TestRedisEntity">
26       SELECT id, name, password
27         FROM test_redis
28           WHERE name = #{name};
29     </select>
30 
31     <insert id="insert" parameterType="com.xiaostudy.shiro_test1.entity.TestRedisEntity" >
32         insert into test_redis (name, password) value (#{name}, #{password});
33     </insert>
34 
35     <update id="update" parameterType="com.xiaostudy.shiro_test1.entity.TestRedisEntity" >
36         update test_redis
37             set
38             name = #{name},
39             password = #{password}
40             where
41             id = #{id};
42     </update>
43 
44     <delete id="deleteById" parameterType="java.lang.Integer" >
45         delete from test_redis
46             where
47              id = #{id};
48     </delete>
49 
50     <delete id="deleteByName" parameterType="java.lang.String" >
51         delete from test_redis
52             where
53              name = #{name};
54     </delete>
55 
56 </mapper>

 

用户mapper,UserMapper.java

 1 package com.xiaostudy.shiro_test1.mapper;
 2 
 3 import com.xiaostudy.shiro_test1.entity.UserEntity;
 4 import org.apache.ibatis.annotations.Mapper;
 5 
 6 /**
 7  * Created with IntelliJ IDEA.
 8  * User: Administrator
 9  * Date: 2019/6/8
10  * Time: 14:45
11  * Description: No Description
12  */
13 @Mapper
14 public interface UserMapper {
15 
16     // 根据用户名称,查询用户信息
17     public UserEntity findByName(String name);
18 
19     // 根据用户id,查询用户信息、角色、权限
20     public UserEntity findById(String id);
21 }

 

测试redis的mapper,TestRedisMapper.java

 1 package com.xiaostudy.shiro_test1.mapper;
 2 
 3 import com.xiaostudy.shiro_test1.entity.TestRedisEntity;
 4 import org.apache.ibatis.annotations.Mapper;
 5 import org.apache.ibatis.annotations.Param;
 6 
 7 import java.util.List;
 8 
 9 /**
10  * Created with IntelliJ IDEA.
11  * User: Administrator
12  * Date: 2019/6/8
13  * Time: 22:07
14  * Description: No Description
15  */
16 @Mapper
17 public interface TestRedisMapper {
18 
19     public List<TestRedisEntity> selectAll();
20 
21     /**
22      * 简单分页
23      * <p>@Param的作用是告诉mapper他的参数名,因为存在多个参数</p>
24      * @param page
25      * @param rows
26      * @return
27      */
28     public List<TestRedisEntity> selectPages(@Param("page") int page, @Param("rows") int rows);
29 
30     public int selectTotal();
31 
32     public TestRedisEntity selectById(int id);
33 
34     public TestRedisEntity selectByName(String name);
35 
36     public int insert(TestRedisEntity testRedisEntity);
37 
38     public int update(TestRedisEntity testRedisEntity);
39 
40     public int deleteById(int id);
41 
42     public int deleteByName(String name);
43 }

 

用户service,UserService.java

 1 package com.xiaostudy.shiro_test1.service;
 2 
 3 import com.xiaostudy.shiro_test1.entity.UserEntity;
 4 
 5 /**
 6  * Created with IntelliJ IDEA.
 7  * User: Administrator
 8  * Date: 2019/6/8
 9  * Time: 14:55
10  * Description: No Description
11  */
12 public interface UserService {
13 
14     UserEntity findByName(String name);
15 
16     UserEntity findById(String id);
17 }

 

测试redis的service,TestRedisService.java

 1 package com.xiaostudy.shiro_test1.service;
 2 
 3 import com.xiaostudy.shiro_test1.entity.TestRedisEntity;
 4 import com.xiaostudy.shiro_test1.entity.UserEntity;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * Created with IntelliJ IDEA.
10  * User: Administrator
11  * Date: 2019/6/8
12  * Time: 14:55
13  * Description: No Description
14  */
15 public interface TestRedisService {
16 
17     public List<TestRedisEntity> selectAll();
18 
19     public List<TestRedisEntity> selectPages(int page, int rows);
20 
21     public int selectTotal();
22 
23     public TestRedisEntity selectById(int id);
24 
25     public TestRedisEntity selectByName(String name);
26 
27     public int insert(TestRedisEntity testRedisEntity);
28 
29     public int update(TestRedisEntity testRedisEntity);
30 
31     public int deleteById(int id);
32 
33     public int deleteByName(String name);
34 }

 

用户service实现类,UserServiceImpl.java

 1 package com.xiaostudy.shiro_test1.service.impl;
 2 
 3 import com.xiaostudy.shiro_test1.entity.UserEntity;
 4 import com.xiaostudy.shiro_test1.mapper.UserMapper;
 5 import com.xiaostudy.shiro_test1.service.UserService;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.stereotype.Service;
 8 
 9 /**
10  * Created with IntelliJ IDEA.
11  * User: Administrator
12  * Date: 2019/6/8
13  * Time: 14:56
14  * Description: No Description
15  */
16 @Service
17 public class UserServiceImpl implements UserService {
18 
19     @Autowired
20     private UserMapper userMapper;
21 
22     @Override
23     public UserEntity findByName(String name) {
24         return userMapper.findByName(name);
25     }
26 
27     @Override
28     public UserEntity findById(String id) {
29         return userMapper.findById(id);
30     }
31 }

 

测试redis的service实现类,TestRedisServiceImpl.java

package com.xiaostudy.shiro_test1.service.impl;

import com.xiaostudy.shiro_test1.entity.TestRedisEntity;
import com.xiaostudy.shiro_test1.entity.UserEntity;
import com.xiaostudy.shiro_test1.mapper.TestRedisMapper;
import com.xiaostudy.shiro_test1.mapper.UserMapper;
import com.xiaostudy.shiro_test1.service.TestRedisService;
import com.xiaostudy.shiro_test1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: Administrator
 * Date: 2019/6/8
 * Time: 14:56
 * Description: No Description
 */
@Service
public class TestRedisServiceImpl implements TestRedisService {

    @Autowired
    private TestRedisMapper testRedisMapper;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Override
    public List<TestRedisEntity> selectAll() {
        List<TestRedisEntity> redisEntityList = (List<TestRedisEntity>) redisTemplate.opsForValue().get("testRedisAll");
        if(null == redisEntityList) {
            redisEntityList = testRedisMapper.selectAll();
            redisTemplate.opsForValue().set("testRedisAll", redisEntityList);
        }
        return redisEntityList;
    }

    @Override
    public List<TestRedisEntity> selectPages(int page, int rows) {
        int current = (page-1)*rows;
        List<TestRedisEntity> redisEntityList = (List<TestRedisEntity>) redisTemplate.opsForValue().get("testRedisByPages_page" + page + "_rows" + rows);
        if(null == redisEntityList) {
            redisEntityList = testRedisMapper.selectPages(current, rows);
            redisTemplate.opsForValue().set("testRedisByPages_page" + page + "_rows" + rows, redisEntityList);
        }
        return redisEntityList;
    }

    @Override
    public int selectTotal() {
        String strTotal = (String) redisTemplate.opsForValue().get("testRedisTotal");
        int total;
        if(null == strTotal) {
            total = testRedisMapper.selectTotal();
            redisTemplate.opsForValue().set("testRedisTotal",String.valueOf(total));
        } else {
            total = Integer.parseInt(strTotal);
        }
        return total;
    }

    @Override
    public TestRedisEntity selectById(int id) {
        TestRedisEntity testRedisEntity = (TestRedisEntity) redisTemplate.opsForValue().get("testRedisById_" + id);
        if(null == testRedisEntity) {
            testRedisEntity = testRedisMapper.selectById(id);
            redisTemplate.opsForValue().set("testRedisById_" + id, testRedisEntity);
        }
        return testRedisEntity;
    }

    @Override
    public TestRedisEntity selectByName(String name) {
        TestRedisEntity testRedisEntity = (TestRedisEntity) redisTemplate.opsForValue().get("testRedisByName_" + name);
        if(null == testRedisEntity) {
            testRedisEntity = testRedisMapper.selectByName(name);
            redisTemplate.opsForValue().set("testRedisByName_" + name, testRedisEntity);
        }
        return testRedisEntity;
    }

    @Override
    public int insert(TestRedisEntity testRedisEntity) {
        int insert = testRedisMapper.insert(testRedisEntity);
        this.closeRedis(insert, "testRedisByPages");
        redisTemplate.opsForValue().set("testRedisTotal",String.valueOf(testRedisMapper.selectTotal()));
        return insert;
    }

    @Override
    public int update(TestRedisEntity testRedisEntity) {
        int update = testRedisMapper.update(testRedisEntity);
        this.closeRedis(update, "testRedisByPages");
        redisTemplate.opsForValue().set("testRedisById_" + testRedisEntity.getId(), testRedisEntity);
        redisTemplate.opsForValue().set("testRedisByName_" + testRedisEntity.getName(), testRedisEntity);
        return update;
    }

    @Override
    public int deleteById(int id) {
        TestRedisEntity testRedisEntity = this.selectById(id);
        int deleteById = testRedisMapper.deleteById(id);
        this.closeRedis(deleteById, "testRedisByPages");
        this.closeRedis(deleteById, "testRedisTotal");
        this.closeRedis(deleteById, "testRedisById_" + id);
        this.closeRedis(deleteById, "testRedisByName_" + testRedisEntity.getName());
        return deleteById;
    }

    @Override
    public int deleteByName(String name) {
        TestRedisEntity testRedisEntity1 = this.selectByName(name);
        int deleteByName = testRedisMapper.deleteByName(name);
        this.closeRedis(deleteByName, "testRedisByPages");
        this.closeRedis(deleteByName, "testRedisTotal");
        this.closeRedis(deleteByName, "testRedisByName_" + name);
        this.closeRedis(deleteByName, "testRedisById_" + testRedisEntity1.getId());
        return deleteByName;
    }

    /**
     * 清空对应实体的缓存
     * @param count
     */
    private void closeRedis(int count, String str) {
        if(0 != count) {
            redisTemplate.delete(redisTemplate.keys(str + "*"));
        }
    }
}

 

用户登录controller,MainController.java

 1 package com.xiaostudy.shiro_test1.web.controller;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.AuthenticationException;
 5 import org.apache.shiro.authc.IncorrectCredentialsException;
 6 import org.apache.shiro.authc.UnknownAccountException;
 7 import org.apache.shiro.authc.UsernamePasswordToken;
 8 import org.apache.shiro.subject.Subject;
 9 import org.springframework.stereotype.Controller;
10 import org.springframework.web.bind.annotation.RequestMapping;
11 
12 import javax.servlet.http.HttpServletRequest;
13 import javax.servlet.http.HttpServletResponse;
14 
15 /**
16  * 用户登录、登出、错误页面跳转控制器
17  * Created with IntelliJ IDEA.
18  * User: Administrator
19  * Date: 2019/6/8
20  * Time: 15:15
21  * Description: No Description
22  */
23 @Controller
24 public class MainController {
25 
26     @RequestMapping("/index")
27     public String index(HttpServletRequest request, HttpServletResponse response){
28         response.setHeader("root", request.getContextPath());
29         return "index";
30     }
31 
32     @RequestMapping("/login")
33     public String login(HttpServletRequest request, HttpServletResponse response){
34         response.setHeader("root", request.getContextPath());
35         String userName = request.getParameter("username");
36         String password = request.getParameter("password");
37 
38         // 等于null说明用户没有登录,只是拦截所有请求到这里,那就直接让用户去登录页面,就不认证了。
39         // 如果这里不处理,那个会返回用户名不存在,逻辑上不合理,用户还没登录怎么就用户名不存在?
40         if(null == userName) {
41             return "login";
42         }
43 
44         // 1.获取Subject
45         Subject subject = SecurityUtils.getSubject();
46         // 2.封装用户数据
47         UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
48         // 3.执行登录方法
49         try{
50             subject.login(token);
51             return "redirect:/index";
52         } catch (UnknownAccountException e){
53             // 这里是捕获自定义Realm的用户名不存在异常
54             request.setAttribute("msg","用户名不存在!");
55         } catch (IncorrectCredentialsException e){
56             request.setAttribute("userName",userName);
57             request.setAttribute("msg","密码错误!");
58         } catch (AuthenticationException e) {
59             // 这里是捕获自定义Realm的认证失败异常
60             request.setAttribute("msg","认证失败!");
61         }
62 
63         return "login";
64     }
65 
66     @RequestMapping("/logout")
67     public String logout(){
68         Subject subject = SecurityUtils.getSubject();
69         if (subject != null) {
70             subject.logout();
71         }
72 //        return "redirect:/main";
73         return "login";
74     }
75 
76     @RequestMapping("/error/unAuth")
77     public String unAuth(){
78         return "/error/unAuth";
79     }
80 
81     @RequestMapping("/err")
82     public String err(){
83         return "/error/unAuth";
84     }
85 }

 

用户权限controller,UserController.java

 1 package com.xiaostudy.shiro_test1.web.controller;
 2 
 3 import com.xiaostudy.shiro_test1.entity.UserEntity;
 4 import org.apache.shiro.SecurityUtils;
 5 import org.apache.shiro.authz.annotation.RequiresPermissions;
 6 import org.springframework.stereotype.Controller;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 
 9 import javax.servlet.http.HttpServletRequest;
10 
11 /**
12  * 用户页面跳转
13  * Created with IntelliJ IDEA.
14  * User: Administrator
15  * Date: 2019/6/8
16  * Time: 15:21
17  * Description: No Description
18  */
19 @Controller
20 public class UserController {
21 
22     /**
23      * 个人中心,需认证可访问
24      */
25     @RequestMapping("/user/index")
26     @RequiresPermissions(value = "user")// 这里的user,就是对应权限实体类PermissionEntity的字段url,自定义Realm类UserRealm里是用这个字段
27     public String add(HttpServletRequest request){
28         UserEntity bean = (UserEntity) SecurityUtils.getSubject().getPrincipal();
29         request.setAttribute("userName", bean.getName());
30         return "/user/index";
31     }
32 
33     /**
34      * 会员中心,需认证且角色为vip可访问
35      */
36     @RequestMapping("/vip/index")
37     @RequiresPermissions(value = "vip")
38     public String update(){
39         return "/vip/index";
40     }
41 }

 

测试redis的controller,TestRedisController.java

  1 package com.xiaostudy.shiro_test1.web.controller;
  2 
  3 import com.xiaostudy.shiro_test1.entity.TestRedisEntity;
  4 import com.xiaostudy.shiro_test1.entity.UserEntity;
  5 import com.xiaostudy.shiro_test1.service.TestRedisService;
  6 import org.apache.shiro.SecurityUtils;
  7 import org.apache.shiro.authz.annotation.RequiresPermissions;
  8 import org.springframework.beans.factory.annotation.Autowired;
  9 import org.springframework.stereotype.Controller;
 10 import org.springframework.ui.Model;
 11 import org.springframework.web.bind.annotation.RequestMapping;
 12 import org.springframework.web.bind.annotation.ResponseBody;
 13 
 14 import javax.servlet.http.HttpServletRequest;
 15 import java.util.HashMap;
 16 import java.util.List;
 17 import java.util.Map;
 18 
 19 /**
 20  * 用户页面跳转
 21  * Created with IntelliJ IDEA.
 22  * User: Administrator
 23  * Date: 2019/6/8
 24  * Time: 15:21
 25  * Description: No Description
 26  */
 27 @Controller
 28 @RequestMapping("/testRedis")
 29 public class TestRedisController {
 30 
 31     @Autowired
 32     private TestRedisService testRedisService;
 33 
 34     @RequestMapping("/index")
 35     public String index() {
 36         return "testRedis/index";
 37     }
 38 
 39     @RequestMapping("/all")
 40     @ResponseBody
 41     public Map getTestRedisAll() {
 42         List<TestRedisEntity> redisEntityList = testRedisService.selectAll();
 43         Map map = new HashMap();
 44         map.put("redisEntityList", redisEntityList);
 45         return map;
 46     }
 47 
 48     @RequestMapping("/pages")
 49     @ResponseBody
 50     public Map getTestRedisPages(String page, String rows) {
 51         List<TestRedisEntity> redisEntityList = testRedisService.selectPages(Integer.parseInt(page), Integer.parseInt(rows));
 52         int total = testRedisService.selectTotal();
 53         Map map = new HashMap();
 54         map.put("redisEntityList", redisEntityList);
 55         map.put("pages", total/Integer.parseInt(rows)+((total%Integer.parseInt(rows) == 0) ? 0 : 1));
 56         map.put("total", total);
 57         map.put("current", Integer.parseInt(page));
 58         return map;
 59     }
 60 
 61     @RequestMapping("/getByName")
 62     @ResponseBody
 63     public Map getByName(String name) {
 64         TestRedisEntity testRedisEntity = testRedisService.selectByName(name);
 65         Map map = new HashMap();
 66         map.put("redisEntity", testRedisEntity);
 67         return map;
 68     }
 69 
 70     @RequestMapping("/get")
 71     @ResponseBody
 72     public Map getTestRedisByName(String name) {
 73         TestRedisEntity testRedisEntity = testRedisService.selectByName(name);
 74         Map map = new HashMap();
 75         map.put("testRedisEntity", testRedisEntity);
 76         return map;
 77     }
 78 
 79     @RequestMapping("/insert")
 80     @ResponseBody
 81     @RequiresPermissions(value = "vip")
 82     public Map insertTestRedis(TestRedisEntity testRedisEntity) {
 83         int insert = testRedisService.insert(testRedisEntity);
 84         Map map = new HashMap();
 85         map.put("result", insert);
 86         return map;
 87     }
 88 
 89     @RequestMapping("/update")
 90     @ResponseBody
 91     @RequiresPermissions(value = "vip")
 92     public Map updateTestRedis(TestRedisEntity testRedisEntity) {
 93         int update = testRedisService.update(testRedisEntity);
 94         Map map = new HashMap();
 95         map.put("result", update);
 96         return map;
 97     }
 98 
 99     @RequestMapping("/deleteById")
100     @ResponseBody
101     @RequiresPermissions(value = "vip")
102     public Map deleteById(String id) {
103         int deleteById = testRedisService.deleteById(Integer.parseInt(id));
104         Map map = new HashMap();
105         map.put("result", deleteById);
106         return map;
107     }
108 
109     @RequestMapping("/deleteByName")
110     @ResponseBody
111     @RequiresPermissions(value = "vip")
112     public Map deleteByName(String name) {
113         int deleteByName = testRedisService.deleteByName(name);
114         Map map = new HashMap();
115         map.put("result", deleteByName);
116         return map;
117     }
118 
119     @RequestMapping("/form")
120     public String form() {
121         return "testRedis/form";
122     }
123 }

 

springboot启动类,ShiroTest1Application.java添加自定义序列化类bean,不要这个也可以,但是在redis上看就是\x\x\x之类

 1 package com.xiaostudy.shiro_test1;
 2 
 3 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 4 import com.fasterxml.jackson.annotation.PropertyAccessor;
 5 import com.fasterxml.jackson.databind.ObjectMapper;
 6 import org.springframework.boot.SpringApplication;
 7 import org.springframework.boot.autoconfigure.SpringBootApplication;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.data.redis.connection.RedisConnectionFactory;
10 import org.springframework.data.redis.core.RedisTemplate;
11 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
12 import org.springframework.data.redis.serializer.StringRedisSerializer;
13 
14 @SpringBootApplication
15 //@MapperScan(basePackages = "com.xiaostudy.shiro_test1.mapper")
16 public class ShiroTest1Application {
17 
18     public static void main(String[] args) {
19         SpringApplication.run(ShiroTest1Application.class, args);
20     }
21 
22     /**
23      * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
24      * @param redisConnectionFactory
25      * @return
26      */
27     @Bean
28     public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
29         RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
30         redisTemplate.setConnectionFactory(redisConnectionFactory);
31 
32         // 使用Jackson2JsonRedisSerialize 替换默认序列化
33         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
34 
35         ObjectMapper objectMapper = new ObjectMapper();
36         objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
37         objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
38 
39         jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
40 
41         // 设置value的序列化规则和 key的序列化规则
42         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
43         redisTemplate.setKeySerializer(new StringRedisSerializer());
44         redisTemplate.afterPropertiesSet();
45         return redisTemplate;
46     }
47 }

 

web.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 5          version="4.0">
 6     <display-name>Archetype Created Web Application</display-name>
 7 
 8     <!--请求编码设置-->
 9     <filter>
10         <filter-name>encodingFilter</filter-name>
11         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
12         <init-param>
13             <param-name>encoding</param-name>
14             <param-value>UTF-8</param-value>
15         </init-param>
16         <init-param>
17             <param-name>forceEncoding</param-name>
18             <param-value>true</param-value>
19         </init-param>
20     </filter>
21     <filter-mapping>
22         <filter-name>encodingFilter</filter-name>
23         <url-pattern>/*</url-pattern>
24     </filter-mapping>
25 
26     <listener>
27         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
28     </listener>
29     <listener>
30         <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
31     </listener>
32     <servlet>
33         <servlet-name>SpringMVC</servlet-name>
34         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
35         <init-param>
36             <param-name>contextConfigLocation</param-name>
37             <param-value>classpath:spring-mvc.xml</param-value>
38         </init-param>
39         <load-on-startup>1</load-on-startup>
40         <async-supported>true</async-supported>
41     </servlet>
42     <servlet-mapping>
43         <servlet-name>SpringMVC</servlet-name>
44         <url-pattern>/</url-pattern>
45     </servlet-mapping>
46     <welcome-file-list>
47         <welcome-file>/index</welcome-file>
48     </welcome-file-list>
49 
50     <servlet-mapping>
51         <servlet-name>default</servlet-name>
52         <url-pattern>*.css</url-pattern>
53     </servlet-mapping>
54     <servlet-mapping>
55         <servlet-name>default</servlet-name>
56         <url-pattern>*.gif</url-pattern>
57     </servlet-mapping>
58     <servlet-mapping>
59         <servlet-name>default</servlet-name>
60         <url-pattern>*.jpg</url-pattern>
61     </servlet-mapping>
62     <servlet-mapping>
63         <servlet-name>default</servlet-name>
64         <url-pattern>*.js</url-pattern>
65     </servlet-mapping>
66 </web-app>

 

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.2.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <!-- 把Controller交给spring管理 -->
    <context:component-scan base-package="com.xiaostudy"/>

    <!-- 配置注解处理器映射器 功能:寻找执行类Controller -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

    <!-- 配置注解处理器适配器 功能:调用controller方法,执行controller -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

    <!-- 配置sprigmvc视图解析器:解析逻辑试图
         后台返回逻辑试图:index
        视图解析器解析出真正物理视图:前缀+逻辑试图+后缀====/WEB-INF/index.jsp -->
    <!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>-->
</beans>

 

application.yml

 1 spring:
 2     datasource:
 3         url: jdbc:mysql://localhost:3306/my_test?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
 4         username: root
 5         password: root
 6         driver-class-name: com.mysql.cj.jdbc.Driver
 7         type: com.alibaba.druid.pool.DruidDataSource
 8         # 初始化时建立物理连接连接的个数
 9         initialSize: 5
10         # 最小连接池数量
11         minIdle: 5
12         # 最大连接池数量
13         maxActive: 20
14         # 获取连接时最大等待时间(ms),即60s
15         maxWait: 60000
16         # 1.Destroy线程会检测连接的间隔时间;2.testWhileIdle的判断依据
17         timeBetweenEvictionRunsMillis: 60000
18         # 最小生存时间ms
19         minEvictableIdleTimeMillis: 600000
20         maxEvictableIdleTimeMillis: 900000
21         # 用来检测连接是否有效的sql
22         validationQuery: SELECT 1 FROM DUAL
23         # 申请连接时执行validationQuery检测连接是否有效,启用会降低性能
24         testOnBorrow: false
25         # 归还连接时执行validationQuery检测连接是否有效,启用会降低性能
26         testOnReturn: false
27         # 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,
28         # 执行validationQuery检测连接是否有效,不会降低性能
29         testWhileIdle: true
30         # 是否缓存preparedStatement,mysql建议关闭
31         poolPreparedStatements: false
32         # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
33         filters: stat,wall,log4j
34     thymeleaf:
35         suffix: .html
36         charset: utf-8
37         #清除缓存,实现热部署
38         cache: false
39     mvc:
40         # 配置静态资源映射路径,/public、/resources路径失效
41         static-path-pattern: templates/**
42 
43     #redis配置
44     redis:
45       host: 127.0.0.1
46       port: 6379
47       password:
48       database: 2
49       timeout: 3000ms
50       jedis:
51         pool:
52           max-active: 200
53           max-idle: 100
54           min-idle: 1
55           max-wait: 3000ms
56 
57 mybatis:
58     mapper-locations: classpath:mapper/*.xml
59 #    mapperLocations: classpath:mapper/*.xml
60     # 虽然可以配置这项来进行pojo包扫描,但其实我更倾向于在mapper.xml写全类名
61 #    type-aliases-package: com.xiaostudy.shiro_test1.entity
62 
63 # 后台打印sql
64 logging:
65   level:
66      com.xiaostudy.shiro_test1.mapper : debug

 

登录页面,login.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>登录</title>
 6 </head>
 7 <body>
 8 <h1>用户登录</h1>
 9 <hr>
10 <form id="from" action="/login" method="post">
11     <table>
12         <tr>
13             <td>用户名</td>
14             <td>
15                 <input type="text" name="username" placeholder="请输入账户名" value="" th:value="${userName }"/>
16             </td>
17         </tr>
18         <tr>
19             <td>密码</td>
20             <td>
21                 <input type="password" name="password" placeholder="请输入密码"/>
22             </td>
23         </tr>
24         <tr>
25             <td colspan="2">
26                 <span style="color: red;">[[${msg }]]</span>
27             </td>
28         </tr>
29         <tr>
30             <td colspan="2">
31                 <input type="submit" value="登录"/>
32                 <input type="reset" value="重置"/>
33             </td>
34         </tr>
35     </table>
36 </form>
37 </body>
38 </html>

 

主页,index.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"
 3       xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
 4 
 5 <head>
 6     <title>首页</title>
 7 </head>
 8 <body>
 9 <h1>首页</h1>
10 <hr>
11 <ul>
12     <li><a href="user/index">个人中心</a></li>
13     <li><a href="vip/index">会员中心</a></li>
14     <p shiro:hasPermission="svip"><li>这是svip能看到的p标签</li></p>
15     <shiro:hasPermission name="vip"><li>这是vip能看到的</li></shiro:hasPermission>
16     <shiro:hasPermission name="svip"><li>这是svip能看到的</li></shiro:hasPermission>
17     <li><a href="testRedis/index">测试redis主页</a></li>
18     <li><a href="logout">退出登录</a></li>
19 </ul>
20 </body>
21 </html>

 

通过认证后普通用户可以访问,user/index.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <title>用户中心</title>
 5 </head>
 6 <body>
 7 <h1>用户中心</h1>
 8 <hr>
 9 <h1>欢迎[[${userName }]],这里是用户中心</h1>
10 </body>
11 </html>

 

通过认证后,vip用户可以访问,vip/index.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <title>会员中心</title>
 5 </head>
 6 <body>
 7 <h1>会员中心</h1>
 8 <hr>
 9 <h1>欢迎来到<span style="color: red;">会员中心</span></h1>
10 </body>
11 </html>

 

认证通过后,普通用户访问vip页面时跳转提示没有权限,error/unAuth.html

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4     <title>未授权提示</title>
5 </head>
6 <body>
7 <h1>您还不是<span style="color: red;">会员</span> ,没有权限访问这个页面!</h1>
8 </body>
9 </html>

 

认证通过后,所有用户可以访问,测试redis主页,testRedis/index.html

  1 <!DOCTYPE html>
  2 <html lang="en" xmlns:th="http://www.thymeleaf.org"
  3       xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
  4 
  5 <head>
  6     <title>首页</title>
  7     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  8     <meta http-equiv="X-UA-Compatible" content="IE=8">
  9     <meta http-equiv="Expires" content="0">
 10     <meta http-equiv="Pragma" content="no-cache">
 11     <meta http-equiv="Cache-control" content="no-cache">
 12     <meta http-equiv="Cache" content="no-cache">
 13 
 14     <script src="" th:src="@{/statics/js/jquery-3.0.0.js}"></script>
 15     <!--jqueryui-->
 16     <link href="//cdn.bootcss.com/jqueryui/1.12.0-rc.2/jquery-ui.min.css" th:href="@{/statics/jquery-ui-1.12.0-rc.2/jquery-ui.min.css}" rel="stylesheet">
 17     <!--jqgrid的css-->
 18     <link href="//cdn.bootcss.com/jqgrid/4.6.0/css/ui.jqgrid.css" th:href="@{/statics/jquery.jqGrid-4.6.0/css/ui.jqgrid.css}" rel="stylesheet">
 19 
 20     <!--locale-->
 21     <script src="//cdn.bootcss.com/jqgrid/4.6.0/js/i18n/grid.locale-en.js" th:src="@{/statics/jquery.jqGrid-4.6.0/js/i18n/grid.locale-en.js}"></script>
 22     <!--jqgrid的js-->
 23     <script src="//cdn.bootcss.com/jqgrid/4.6.0/js/jquery.jqGrid.min.js" th:src="@{/statics/jquery.jqGrid-4.6.0/js/jquery.jqGrid.min.js}"></script>
 24     <link href="" th:href="@{/statics/layui/css/layui.css}" rel="stylesheet">
 25     <script src="" th:src="@{/statics/layui/layui.all.js}"></script>
 26 </head>
 27 <body>
 28 <h1>测试redis</h1>
 29 <hr>
 30 <shiro:hasPermission name="vip">
 31     <button type="button" class="layui-btn" title="添加" onclick="create()">添加</button>
 32 </shiro:hasPermission>
 33 <shiro:hasPermission name="vip">
 34     <input type="hidden" id="vip">
 35 </shiro:hasPermission>
 36 <shiro:hasPermission name="svip">
 37     <input type="hidden" id="svip">
 38 </shiro:hasPermission>
 39 <table id="jqGrid" class="layui-table layui-table-grid"></table>
 40 <div id="jqGridPager"></div>
 41 </body>
 42 </html>
 43 
 44 
 45 <script>
 46     $(function () {
 47         $("#jqGrid").jqGrid({
 48             url : '[[${#httpServletRequest.getContextPath()}]]/testRedis/pages',
 49             datatype : "json",
 50             colModel : [
 51                 { label: 'ID', name: 'id', width: 80, hidden:true },
 52                 { label: "名称", name: "name", "align": "center",  width: 100},
 53                 { label: "密码 ", name: "password", "align": "center", width: 100},
 54                 { label: "操作 ", name: "id", "align": "center", width: 100, formatter: operation}
 55             ],
 56             viewrecords : true,
 57             height : 300,
 58             rowNum : 5,
 59             rowList : [5,10,15,20,30,50],
 60             rownumbers : true,
 61             rownumWidth : 35,
 62             autowidth : true,
 63             multiselect : true,
 64             pager : "#jqGridPager",
 65             jsonReader : {
 66                 root : "redisEntityList",
 67                 page : "current",
 68                 total : "pages",
 69                 records : "total"
 70             },
 71             prmNames : {
 72                 page : "page",
 73                 rows : "rows",
 74                 order : "order"
 75             },
 76             postData:{
 77 
 78             },
 79             gridComplete : function() {
 80                 // 隐藏grid底部滚动条
 81                 $("#jqGrid").closest(".ui-jqgrid-bdiv").css({
 82                     "overflow-x" : "hidden"
 83                 });
 84                 //设置行高
 85                 var grid = $("#jqGrid");
 86                 var ids = grid.getDataIDs();
 87                 for (var i = 0; i < ids.length; i++) {
 88                     grid.setRowData ( ids[i], false, {height: 10} );
 89                 }
 90             },
 91             beforeRequest : function (){
 92                 var current=$(this).getGridParam("page");//当前页
 93                 var total= $(this).getGridParam('lastpage'); //获取总页数
 94                 if(current > total && total!=0){
 95                     //设置页码为最后一页 并重新加载
 96                     var postDatas = $(this).jqGrid("getGridParam", "postData");
 97                     postDatas['page']=total;
 98                     $(this).setGridParam({postData:postDatas});
 99                 }
100             },
101             ondblClickRow : function(rowid) {
102                 view(rowid);
103                 /*if(!ondblClickRowSubTable){
104                     archivesFolderJs.view(rowid);
105                 }else{
106                     ondblClickRowSubTable = false;
107                 }*/
108             }
109         });
110 
111         function operation(id) {
112             /*var hrml2 =
113                 ' <div class="layui-btn-group">' +
114                 '                    <button type="button" class="layui-btn" title="查看" onclick="view(\''+id+'\')">查看</button>' +
115                 '                    <button type="button" class="layui-btn" title="编辑" onclick="update(\''+id+'\')">编辑</button>' +
116                 '                    <button type="button" class="layui-btn" title="删除" onclick="deleteById(\''+id+'\')">删除</button>';*/
117             var hrml2 =
118                 ' <div class="layui-btn-group">' +
119                 '                    <button type="button" class="layui-btn" title="查看" onclick="view(\''+id+'\')">查看</button>';
120             if($("#vip").length>0) {
121                 hrml2 = hrml2  + '<button type="button" class="layui-btn" title="编辑" onclick="update(\''+id+'\')">编辑</button>'
122                     + '<button type="button" class="layui-btn" title="删除" onclick="deleteById(\''+id+'\')">删除</button>';
123             }
124             return hrml2;
125         }
126     });
127     
128     function create() {
129         var content = "[[${#httpServletRequest.getContextPath()}]]/testRedis/form";
130 
131         var title ="添加";
132         var btns = [ '确认',  '关闭' ];
133         var width ='700px';
134         var height = '200px';
135         var operation = "add";
136         open(2, title, width, height, 0.5, false, content, btns, operation, "");
137     }
138 
139     function view(id) {
140         var content = "[[${#httpServletRequest.getContextPath()}]]/testRedis/form";
141 
142         var title ="查看";
143         var btns = [ '关闭' ];
144         var width ='700px';
145         var height = '200px';
146         var operation = "view";
147         open(2, title, width, height, 0.5, false, content, btns, operation, id);
148     }
149 
150     function update(id) {
151         var content = "[[${#httpServletRequest.getContextPath()}]]/testRedis/form";
152 
153         var title ="修改";
154         var btns = [ '确认',  '关闭' ];
155         var width ='700px';
156         var height = '200px';
157         var operation = "update";
158         open(2, title, width, height, 0.5, false, content, btns, operation, id);
159     }
160 
161     function deleteById(id) {
162         var content = "[[${#httpServletRequest.getContextPath()}]]/testRedis/form";
163 
164         layer.confirm('确认删除?', {
165             btn: ['确定','取消'] //按钮
166         }, function(){
167             $.get("[[${#httpServletRequest.getContextPath()}]]/testRedis/deleteById?id=" + id
168                 + "&_=" + new Date().getTime(), function (r) {
169                 layer.closeAll();
170                 if(r.result == 1) {
171                     layui.layer.msg("删除成功");
172                     $("#jqGrid").jqGrid().trigger("reloadGrid");
173                 } else {
174                     layui.layer.msg("删除失败");
175                 }
176             });
177         }, function(){
178             // 点击取消事件
179         });
180     }
181 
182     function open(type, title, width, height, shade, maxmin, content, btns, operation, id) {
183         layui.use('layer', function() {
184             var layer = layui.layer;
185             parent.layer.open({
186                 type: type,
187                 title: title,
188                 area: [width, height],
189                 shade: shade,
190                 maxmin: maxmin,
191                 content: content,
192                 btn: btns,
193                 yes: function (index, layero) {
194                     var selector = layero["selector"];
195                     selector = "#layui-layer-iframe" + selector.substring("#layui-layer".length, selector.length);
196                     var name = parent.$(selector).contents().find("#name").val();
197                     var password = parent.$(selector).contents().find("#password").val();
198                     if(undefined == name || null == name || "" == name) {
199                         layui.layer.msg("请输入名称");
200                         return;
201                     }
202                     if(undefined == password || null == password || "" == password) {
203                         layui.layer.msg("请输入密码");
204                         return;
205                     }
206                     if("add" == operation) {
207                         $.get("[[${#httpServletRequest.getContextPath()}]]/testRedis/getByName?name=" + name
208                             + "&_=" + new Date().getTime(), function (r) {
209                             if(null != r.redisEntity && r.redisEntity.name == name) {
210                                 layui.layer.msg("名称已存在");
211                                 return;
212                             } else {
213                                 $.get("[[${#httpServletRequest.getContextPath()}]]/testRedis/insert?name=" + name
214                                     + "&password=" + password + "&_=" + new Date().getTime(), function (r) {
215                                     if(r.result == 1) {
216                                         layer.closeAll();
217                                         layui.layer.msg("添加成功");
218                                         $("#jqGrid").jqGrid().trigger("reloadGrid");
219                                     } else {
220                                         layui.layer.msg("添加失败");
221                                     }
222                                 });
223                             }
224                         });
225                     } else if("update" == operation) {
226                         $.get("[[${#httpServletRequest.getContextPath()}]]/testRedis/update?id=" + id + "&name=" + name
227                             + "&password=" + password + "&_=" + new Date().getTime(), function (r) {
228                             if(r.result == 1) {
229                                 layer.closeAll();
230                                 layui.layer.msg("修改成功");
231                                 $("#jqGrid").jqGrid().trigger("reloadGrid");
232                             } else {
233                                 layui.layer.msg("修改失败");
234                             }
235                         });
236                     } else {
237                         layer.closeAll();
238                     }
239                 },
240 
241                 btn3: function () {
242                     parent.layer.closeAll();
243                     return false;
244                 },
245                 zIndex: 999,
246                 success: function (layero) {
247                     // 弹出窗弹出之前设置数据到弹出窗页面
248                     if("update" == operation) {
249                         var selector = layero["selector"];
250                         selector = "#layui-layer-iframe" + selector.substring("#layui-layer".length, selector.length);
251                         parent.$(selector).contents().find("#id").val(id);
252                         var rowData = $("#jqGrid").jqGrid('getRowData',id);
253                         parent.$(selector).contents().find("#name").val(rowData.name);
254                         parent.$(selector).contents().find("#password").val(rowData.password);
255                     } else if("view" == operation) {
256                         var selector = layero["selector"];
257                         selector = "#layui-layer-iframe" + selector.substring("#layui-layer".length, selector.length);
258                         parent.$(selector).contents().find("#id").val(id);
259                         var rowData = $("#jqGrid").jqGrid('getRowData',id);
260                         var name = parent.$(selector).contents().find("#name");
261                         name.val(rowData.name);
262                         var password = parent.$(selector).contents().find("#password");
263                         password.val(rowData.password);
264                         name.attr("onfocus", "this.blur()");
265                         password.attr("onfocus", "this.blur()");
266                         name.css("background", "#CCCCCC");
267                         name.css("cursor", "not-allowed");
268                         password.css("background", "#CCCCCC");
269                         password.css("cursor", "not-allowed");
270                         /*name.attr("disabled", "disabled");
271                         password.attr("disabled", "disabled");*/
272                     }
273                 }
274             });
275         });
276     }
277 </script>

 

测试redis主页,添加、修改、查看的form页面,testRedis/form.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"
 3       xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>Title</title>
 7     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 8     <meta http-equiv="X-UA-Compatible" content="IE=8">
 9     <meta http-equiv="Expires" content="0">
10     <meta http-equiv="Pragma" content="no-cache">
11     <meta http-equiv="Cache-control" content="no-cache">
12     <meta http-equiv="Cache" content="no-cache">
13 
14     <script src="" th:src="@{/statics/js/jquery-3.0.0.js}"></script>
15     <!--jqueryui-->
16     <link href="//cdn.bootcss.com/jqueryui/1.12.0-rc.2/jquery-ui.min.css" th:href="@{/statics/jquery-ui-1.12.0-rc.2/jquery-ui.min.css}" rel="stylesheet">
17     <!--jqgrid的css-->
18     <link href="//cdn.bootcss.com/jqgrid/4.6.0/css/ui.jqgrid.css" th:href="@{/statics/jquery.jqGrid-4.6.0/css/ui.jqgrid.css}" rel="stylesheet">
19 
20     <!--locale-->
21     <script src="//cdn.bootcss.com/jqgrid/4.6.0/js/i18n/grid.locale-en.js" th:src="@{/statics/jquery.jqGrid-4.6.0/js/i18n/grid.locale-en.js}"></script>
22     <!--jqgrid的js-->
23     <script src="//cdn.bootcss.com/jqgrid/4.6.0/js/jquery.jqGrid.min.js" th:src="@{/statics/jquery.jqGrid-4.6.0/js/jquery.jqGrid.min.js}"></script>
24     <link href="" th:href="@{/statics/layui/css/layui.css}" rel="stylesheet">
25     <script src="" th:src="@{/statics/layui/layui.all.js}"></script>
26 </head>
27 <body>
28 <div class="layui-form" style="margin-top: 30px;margin-right: 20px;">
29     <div class="layui-form-item">
30         <input type="hidden" id="id" name="id" value="">
31         <label class="layui-form-label">名称</label>
32         <div class="layui-input-inline">
33             <input type="text" id="name" name="name" required  lay-verify="required" placeholder="名称" autocomplete="off" class="layui-input">
34         </div>
35         <label class="layui-form-label">密码</label>
36         <div class="layui-input-inline">
37             <input type="text" id="password" name="password" required lay-verify="required" placeholder="密码" autocomplete="off" class="layui-input">
38         </div>
39     </div>
40 </div>
41 
42 <script>
43     //Demo
44     layui.use('form', function(){
45         var form = layui.form;
46 
47         //监听提交
48         form.on('submit(formDemo)', function(data){
49             layer.msg(JSON.stringify(data.field));
50             return false;
51         });
52     });
53 </script>
54 </body>
55 </html>

 

pom.xml

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4     <modelVersion>4.0.0</modelVersion>
  5     <parent>
  6         <groupId>org.springframework.boot</groupId>
  7         <artifactId>spring-boot-starter-parent</artifactId>
  8         <version>2.1.5.RELEASE</version>
  9         <relativePath/> <!-- lookup parent from repository -->
 10     </parent>
 11     <groupId>com.xiaostudy</groupId>
 12     <artifactId>shiro_test1</artifactId>
 13     <version>0.0.1-SNAPSHOT</version>
 14     <name>shiro_test1</name>
 15     <description>Demo project for Spring Boot</description>
 16 
 17     <properties>
 18         <java.version>1.8</java.version>
 19     </properties>
 20 
 21     <dependencies>
 22         <dependency>
 23             <groupId>org.springframework.boot</groupId>
 24             <artifactId>spring-boot-starter-jdbc</artifactId>
 25         </dependency>
 26         <dependency>
 27             <groupId>org.springframework.boot</groupId>
 28             <artifactId>spring-boot-starter-thymeleaf</artifactId>
 29         </dependency>
 30         <dependency>
 31             <groupId>org.springframework.boot</groupId>
 32             <artifactId>spring-boot-starter-web</artifactId>
 33         </dependency>
 34         <dependency>
 35             <groupId>org.mybatis.spring.boot</groupId>
 36             <artifactId>mybatis-spring-boot-starter</artifactId>
 37             <version>2.0.1</version>
 38         </dependency>
 39 
 40         <dependency>
 41             <groupId>mysql</groupId>
 42             <artifactId>mysql-connector-java</artifactId>
 43             <scope>runtime</scope>
 44         </dependency>
 45         <dependency>
 46             <groupId>org.springframework.boot</groupId>
 47             <artifactId>spring-boot-starter-test</artifactId>
 48             <scope>test</scope>
 49         </dependency>
 50 
 51         <!-- 数据库连接池 -->
 52         <dependency>
 53             <groupId>com.alibaba</groupId>
 54             <artifactId>druid</artifactId>
 55             <version>1.1.10</version>
 56         </dependency>
 57         <!-- Shiro -->
 58         <dependency>
 59             <groupId>org.apache.shiro</groupId>
 60             <artifactId>shiro-spring</artifactId>
 61             <version>1.3.2</version>
 62         </dependency>
 63         <!-- log4j -->
 64         <dependency>
 65             <groupId>log4j</groupId>
 66             <artifactId>log4j</artifactId>
 67             <version>1.2.17</version>
 68         </dependency>
 69 
 70         <dependency>
 71             <groupId>com.github.theborakompanioni</groupId>
 72             <artifactId>thymeleaf-extras-shiro</artifactId>
 73             <version>2.0.0</version>
 74         </dependency>
 75 
 76         <!--热部署-->
 77         <dependency>
 78             <groupId>org.springframework.boot</groupId>
 79             <artifactId>spring-boot-devtools</artifactId>
 80             <scope>runtime</scope>
 81         </dependency>
 82 
 83         <!-- redis 包 -->
 84         <dependency>
 85             <groupId>org.springframework.boot</groupId>
 86             <artifactId>spring-boot-starter-data-redis</artifactId>
 87             <version>1.4.7.RELEASE</version>
 88         </dependency>
 89     </dependencies>
 90 
 91     <build>
 92         <plugins>
 93             <plugin>
 94                 <groupId>org.springframework.boot</groupId>
 95                 <artifactId>spring-boot-maven-plugin</artifactId>
 96             </plugin>
 97         </plugins>
 98     </build>
 99 
100 </project>

 

数据库表创建

用户表、角色表、权限表、用户与角色多对多表、角色与权限多对多表

 1  DROP TABLE IF EXISTS `role_permission`;
 2  DROP TABLE IF EXISTS `permission`;
 3  DROP TABLE IF EXISTS `user_role`;
 4  DROP TABLE IF EXISTS `role`;
 5  DROP TABLE IF EXISTS `user`;
 6 
 7  CREATE TABLE `user` (
 8  `id` VARCHAR(255) PRIMARY KEY,
 9  `name` VARCHAR(255),
10  `password` VARCHAR(255)
11  ) engine = InnoDB default charset = utf8 comment = '用户表';
12 
13  CREATE TABLE `role` (
14  `id` VARCHAR(255) PRIMARY KEY,
15  `name` VARCHAR(255)
16  ) engine = InnoDB default charset = utf8 comment = '角色表';
17 
18  CREATE TABLE `user_role` (
19  `id` VARCHAR(255) PRIMARY KEY,
20  `user_id` VARCHAR(255),
21  `role_id` VARCHAR(255),
22  FOREIGN KEY (`user_id`) REFERENCES `user`(id),
23  FOREIGN KEY (`role_id`) REFERENCES `role`(id)
24  ) engine = InnoDB default charset = utf8 comment = '用户与角色多对多表';
25 
26  CREATE TABLE `permission` (
27  `id` VARCHAR(255) PRIMARY KEY,
28  `name` VARCHAR(255),
29  `url` VARCHAR(255)
30  ) engine = InnoDB default charset = utf8 comment = '权限表';
31 
32  CREATE TABLE `role_permission` (
33  `id` VARCHAR(255) PRIMARY KEY,
34  `role_id` VARCHAR(255),
35  `permission_id` VARCHAR(255),
36  FOREIGN KEY (`role_id`) REFERENCES `role`(id),
37  FOREIGN KEY (`permission_id`) REFERENCES `permission`(id)
38  ) engine = InnoDB default charset = utf8 comment = '角色与权限多对多表';
39 
40 insert into `user` (`id`, `name`, `password`) values('1','admin','123456');
41 insert into `user` (`id`, `name`, `password`) values('2','vip','123456');
42 insert into `user` (`id`, `name`, `password`) values('3','svip','1234');
43 
44 insert into `role` (`id`, `name`) values('1','user');
45 insert into `role` (`id`, `name`) values('2','vip');
46 insert into `role` (`id`, `name`) values('3','svip');
47 
48 insert into `permission` (`id`, `name`, `url`) values('1','user','user');
49 insert into `permission` (`id`, `name`, `url`) values('2','vip','vip');
50 insert into `permission` (`id`, `name`, `url`) values('3','svip','svip');
51 
52 insert into `user_role` (`id`, `user_id`, `role_id`) values('1','1','1');
53 insert into `user_role` (`id`, `user_id`, `role_id`) values('2','2','1');
54 insert into `user_role` (`id`, `user_id`, `role_id`) values('3','2','2');
55 insert into `user_role` (`id`, `user_id`, `role_id`) values('4','3','1');
56 insert into `user_role` (`id`, `user_id`, `role_id`) values('5','3','2');
57 insert into `user_role` (`id`, `user_id`, `role_id`) values('6','3','3');
58 
59 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('1','1','1');
60 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('2','2','1');
61 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('3','2','2');
62 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('4','3','1');
63 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('5','3','2');
64 insert into `role_permission` (`id`, `role_id`, `permission_id`) values('6','3','3');

 

测试redis表

1  DROP TABLE IF EXISTS `test_redis`;
2 
3  CREATE TABLE `test_redis` (
4  `id` int(11) PRIMARY KEY auto_increment,
5  `name` VARCHAR(255),
6  `password` VARCHAR(255)
7  ) engine = InnoDB default charset = utf8 comment = '测试redis表';

 

3、layui与jqGrid相关下载

layui官网下载:https://www.layui.com/

jqGrid官网下载:http://www.trirand.com/blog/?page_id=6

jqueryUI官网下载:http://jqueryui.com/download/all/

jquery下载:http://www.jq22.com/jquery-info122

 

4、测试

测试权限的就不在这里重复测试了,可以看一下之前写的文章【直接看最后的测试】:https://www.cnblogs.com/xiaostudy/p/10990999.html

 

 

posted @ 2019-06-09 22:13  xiaostudy  阅读(409)  评论(0编辑  收藏  举报
网站推荐
[理工最爱]小时百科 |  GitHub |  Gitee |  开源中国社区 |  牛客网 |  不学网论坛 |  r2coding |  冷熊简历 |  爱盘 |  零散坑 |  bootstrap中文网 |  vue.js官网教程 |  源码分享站 |  maven仓库 |  楼教主网站 |  廖雪峰网站 |  w3cschool |  在线API |  代码在线运行 |  [不学网]代码在线运行 |  JS在线运行 |  PHP中文网 |  深度开源eclipse插件 |  文字在线加密解密 |  菜鸟教程 |  慕课网 |  千图网 |  手册网 |  素材兔 |  盘多多 |  悦书PDF |  sumatra PDF |  calibre PDF |  Snipaste截图 |  shareX截图 |  vlc-media-player播放器 |  MCMusic player |  IDM下载器 |  格式工厂 |  插件网 |  谷歌浏览器插件 |  Crx搜搜 |  懒人在线计算器 |  leetcode算法题库 |  layer官网 |  layui官网 |  formSelects官网 |  Fly社区 |  程序员客栈 |  融云 |  华为云 |  阿里云 |  ztree官网API |  teamviewer官网 |  sonarlint官网 |  editormd |  pcmark10官网 |  crx4chrome官网 |  apipost官网 |  花生壳官网 |  serv-u官网 |  杀毒eset官网 |  分流抢票bypass官网 |  懒猴子CG代码生成器官网 |  IT猿网 |  natapp[内网穿透] |  ngrok[内网穿透] |  深蓝穿透[内网穿透] |  WakeMeOnLan[查看ip] |  iis7 |  [漏洞扫描]Dependency_Check官网 |  [图标UI]fontawesome官网 |  idea插件官网 |  路过图床官网 |  sha256在线解密 |  在线正则表达式测试 |  在线文件扫毒 |  KuangStudy | 
资源下载
电脑相关: Windows原装下载msdn我告诉你 |  U盘制作微PE工具官网下载 |  Linux_CentOS官网下载 |  Linux_Ubuntu官网下载 |  Linux_OpenSUSE官网下载 |  IE浏览器官网下载 |  firefox浏览器官网下载 |  百分浏览器官网下载 |  谷歌google浏览器历史版本下载 |  深度deepin系统官网下载 |  中兴新支点操作系统官网下载 |  文件对比工具Beyond Compare官网下载 |  开机启动程序startup-delayer官网下载 |  openoffice官网下载 |  utorrent官网下载 |  qbittorrent官网下载 |  cpu-z官网下载 |  蜘蛛校色仪displaycal官网下载 |  单文件制作greenone下载 |  win清理工具Advanced SystemCare官网下载 |  解压bandizip官网下载 |  内存检测工具memtest官网下载 |  磁盘坏道检测与修复DiskGenius官网下载 |  磁盘占用可视化SpaceSniffer官网下载 |  [磁盘可视化]WizTree官网下载 |  win快速定位文件Everything官网下载 |  文件定位listary官网下载 |  动图gifcam官网下载 |  7-Zip官网下载 |  磁盘分区工具diskgenius官网下载 |  CEB文件查看工具Apabi Reader官网下载 |  罗技鼠标options官网下载 |  [去除重复文件]doublekiller官网下载 | 
编程相关: ApacheServer官网下载 |  Apache官网下载 |  Git官网下载 |  Git高速下载 |  Jboss官网下载 |  Mysql官网下载 |  Mysql官网历史版本下载 |  NetBeans IDE官网下载 |  Spring官网下载 |  Nginx官网下载 |  Resin官网下载 |  Tomcat官网下载 |  jQuery历史版本下载 |  nosql官网下载 |  mongodb官网下载 |  mongodb_linux历史版本下载 |  mongodb客户端下载 |  VScode官网下载 |  cxf官网下载 |  maven官网下载 |  QT官网下载 |  SVN官网下载 |  SVN历史版本下载 |  nodeJS官网下载 |  oracle官网下载 |  jdk官网下载 |  STS官网下载 |  STS历史版本官网下载 |  vue官网下载 |  virtualbox官网下载 |  docker desktop官网下载 |  github desktop官网下载 |  EditPlus官网下载 |  zTree下载 |  layui官网下载 |  jqgrid官网下载 |  jqueryui官网下载 |  solr历史版本下载 |  solr分词器ik-analyzer-solr历史版本下载 |  zookeeper历史版本官网下载 |  nssm官网下载 |  elasticsearch官网下载 |  elasticsearch历史版本官网下载 |  redis官网下载 |  redis历史版本官网下载 |  redis的win版本下载 |  putty官网下载 |  查看svn密码TSvnPD官网下载 |  MongoDB连接工具Robo官网下载 |  dll查看exescope官网下载 |  dll2c官网下载 |  接口测试apipost官网下载 |  接口测试postman官网下载 |  原型设计工具AxureRP官网下载 |  canal官网下载 |  idea主题样式下载 |  vue的GitHub下载 |  finalShell官网下载 |  ETL工具kafka官网下载 |  cavaj[java反编译]官网下载 |  jd-gui[java反编译]官网下载 |  radmin[远程连接]官网下载 |  tcping[win ping端口]下载 |  jQueryUploadFile官网下载 |  RedisPlus下载 |  aiXcoder智能编程助手官网下载 |  [表单效验]validform官网下载 |  idea官网下载 |  RedisStudio下载 |  MD转word含公式pandoc官网下载 |  logviewer官网下载 |  Kafka官网下载 |  hbase高速下载 |  hadoop官网下载 |  hadooponwindows的GitHub下载 |  hive官网下载 |  soapui官网下载 |  flink官网下载 |  kafkatool官网下载 |  MinIO官网下载 |  MinIO中国镜像下载 | 
办公相关工具
免费在线拆分PDF【不超过30M】 |  免费在线PDF转Word【不超过10M】 |  在线文字识别转换【不超过1M】 |  PDF转换成Word【不超过50M】 |  在线OCR识别 |  Smallpdf |  文件转换器Convertio |  迅捷PDF转换器 |  字母大小写转换工具 |  档铺 |  快传airportal[可文字] |  快传-文叔叔 |  P2P-小鹿快传 |  [图床]ImgURL | 
网站入口
腾讯文档 |  有道云笔记网页版 |  为知笔记网页版 |  印象笔记网页版 |  蓝奏云 |  QQ邮箱 |  MindMaster在线思维导图 |  bilibili |  PDM文件在线打开 |  MPP文件在线打开 |  在线PS软件 |  在线WPS |  阿里云企业邮箱登陆入口 | 
其他
PDF转换 |  悦书PDF转换 |  手机号注册查询 |  Reg007 |  akmsg |  ip8_ip查询 |  ipip_ip查询 |  天体运行testtubegames |  测试帧率 |  在线网速测试 |