springboot+shiro(JWT管理)(一)简单实例

一、代码:采用dubbo+shiro,这里dubbo的service层和api层就不看了

springboot+shiro(JWT管理)(一)简单实例_第1张图片

springboot+shiro(JWT管理)(一)简单实例_第2张图片

 

1、pom:



    4.0.0

    org.example
    shiro-jwt
    1.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        1.4.1.RELEASE
    

    

        
        
            com.demo
            mysercurity-api
            1.0.0-SNAPSHOT
        

        
        
            com.alibaba.spring.boot
            dubbo-spring-boot-starter
            2.0.0
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        
            redis.clients
            jedis
        
        
        
            org.apache.httpcomponents
            httpclient
            4.5.6
        

        
            com.github.pagehelper
            pagehelper
            5.1.8
        

        
            com.alibaba
            fastjson
            1.2.31
        

        
            commons-collections
            commons-collections
            3.2.1
        
        
            commons-lang
            commons-lang
            2.5
        

        
        
            com.github.sgroschupf
            zkclient
            0.1
            
                
                    log4j
                    log4j
                
                
                    slf4j-log4j12
                    org.slf4j
                
            
        

        
        
            com.aliyun.oss
            aliyun-sdk-oss
            2.8.3
        

        
        
            org.apache.shiro
            shiro-core
            1.2.2
        
        
            org.apache.shiro
            shiro-spring
            1.2.2
        
        
            org.apache.shiro
            shiro-ehcache
            1.2.2
        

        
            com.auth0
            java-jwt
            3.7.0
        


    
    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/libs-milestone
            
                false
            
        
    

2、配置文件

application.properties:

server.port=7777
server.context-path=/shirodemo
my.redis.server.host=127.0.0.1
my.redis.server.port=6379
my.redis.server.password = wtyy
my.redis.server.jedis.pool.maxTotal=500
my.redis.server.jedis.pool.maxIdle=10
my.redis.server.jedis.pool.maxWaitMillis=5000
my.redis.server.jedis.pool.min-idle=5
my.redis.server.timeout=5000 



ehcache.xml:



    

    
    

consume.xml:



    
    
    

    
    
    


 3、启动类:

package com.shiro.jwt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource("classpath:consumer.xml")
public class Application {
    public static void main(String args[]){
        SpringApplication.run(Application.class,args);
    }
}

4、config配置:

(1)redis配置

package com.shiro.jwt.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.support.collections.RedisProperties;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisConfig {

    private Logger logger = LoggerFactory.getLogger(JedisConfig.class);

    @Value("${my.redis.server.host}")
    private String host;

    @Value("${my.redis.server.port}")
    private int port;

    @Value("${my.redis.server.password}")
    private String password;

    @Value("${my.redis.server.jedis.pool.maxTotal}")
    private int maxTotal;

    @Value("${my.redis.server.jedis.pool.maxIdle}")
    private int maxIdle;

    @Value("${my.redis.server.jedis.pool.maxWaitMillis}")
    private int maxWaitMillis;

    @Value("${my.redis.server.timeout}")
    private int timeout;

    @Bean(name = "jedisPool")
    public JedisPool jedisPool() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMaxWaitMillis(maxWaitMillis);
        return new JedisPool(config, host, port, timeout);
    }

}

(2)前端跨越配置:

package com.shiro.jwt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    //配置前端跨越
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedHeaders("*")
                .allowedMethods("*")
                .allowedOrigins("*")
                .allowCredentials(true);
    }


}

(3)shiro配置入口:

package com.shiro.jwt.config;

import com.shiro.jwt.handler.JwtFilter;
import com.shiro.jwt.realms.MyShiroRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Autowired
    private CacheManager cacheManager;

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager((SecurityManager) securityManager);
        Map filterChainDefinitionMap = new LinkedHashMap();
        //注意过滤器配置顺序
        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl,
        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/code/getCode", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        //剩下接口全部需要认证
        filterChainDefinitionMap.put("/**", "authc");

        LinkedHashMap filtsMap=new LinkedHashMap();
        filtsMap.put("authc",new JwtFilter() );
        shiroFilterFactoryBean.setFilters(filtsMap);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm realm = new MyShiroRealm();
        realm.setCacheManager(getEhCacheManager());
        return realm;
    }

    @Bean
    public EhCacheManager getEhCacheManager(){
        EhCacheManager ehcacheManager = new EhCacheManager();
        ehcacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return ehcacheManager;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        /*
         * 关闭shiro自带的session,详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);

        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }


    /**
     * 开启shiro aop注解支持
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        System.out.println("开启shiro注解");
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
    /**
     * 自动创建代理
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    /**
     * 注册全局异常处理
     * @return
     */
}

5、dto:

(1)常量:

package com.shiro.jwt.dto;

public class CommonConstant {

   //redis缓存过期时间
    public static final int EXPIRE_TIME = 30 * 60 * 1000;

    //前端携带token的header的key名称
    public static final String ACCESS_TOKEN = "token";

    public static final String USER_TOKEN = "USER_TOKEN:{userAccount}";

}

(2) 返回实体:

package com.shiro.jwt.dto;



public class ResponseMessage {

    private int code;

    private String status;

    private String message;

    private String errorMessage;

    private String errorExceptionMessage;

    private Object data;

    public ResponseMessage(int code, String status, Object data){
        this.code = code;
        this.status = status;
        this.data = data;
    }

    public ResponseMessage(int code, String status, String message){
        this.code = code;
        this.status = status;
        this.message = message;
    }

    public ResponseMessage(int code, String status, String message, Object data){
        this.code = code;
        this.status = status;
        this.message = message;
        this.data = data;
    }




    public ResponseMessage(int code, String status, String message, String errorMessage){
        this.code = code;
        this.status = status;
        this.message = message;
        this.errorMessage = errorMessage;
    }

    public ResponseMessage(int code, String status, String message, String errorMessage, String errorExceptionMessage){
        this.code = code;
        this.status = status;
        this.message = message;
        this.errorMessage = errorMessage;
        this.errorExceptionMessage = errorExceptionMessage;
    }


    public static ResponseMessage  success(String message){
        return new ResponseMessage(CommonEnums.CODE_200.code,"success",message);
    }
    public static ResponseMessage  success(Object data){
        return new ResponseMessage(CommonEnums.CODE_200.code,"success",data);
    }


    public static ResponseMessage  success(String message,Object data){
        return new ResponseMessage(CommonEnums.CODE_200.code,"success",message,data);
    }

    public static ResponseMessage  success(int code,String message,Object data){
        return new ResponseMessage(code,"success",message,data);
    }

    public static ResponseMessage  success(){
        return new ResponseMessage(CommonEnums.CODE_200.code,null,CommonEnums.CODE_200.message);
    }

    public static  ResponseMessage success(int code,Object data){
        return new ResponseMessage(code,"success",data);
    }


    public static ResponseMessage success(int code,String message){
        return new ResponseMessage(code,"success",message);
    }

    public static  ResponseMessage error(int code,String message){
        return new ResponseMessage(code,"error",message);
    }

    public static  ResponseMessage error(int code,String message,String errorMessage){
        return new ResponseMessage(code,"error",message,errorMessage);
    }

    public static  ResponseMessage error(int code,String message,String errorMessage,String errorExceptionMessage){
        return new ResponseMessage(code,"error",message,errorMessage,errorExceptionMessage);
    }


    public static  ResponseMessage error(String message,String errorMessage){
        return new ResponseMessage(CommonEnums.CODE_500.code,"error",message,errorMessage);
    }

    public static  ResponseMessage error(String message){
        return new ResponseMessage(CommonEnums.CODE_400.code,"error",message);
    }

    public static  ResponseMessage infor(int code,String message){
        return new ResponseMessage(code,"infor",message);
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getErrorExceptionMessage() {
        return errorExceptionMessage;
    }

    public void setErrorExceptionMessage(String errorExceptionMessage) {
        this.errorExceptionMessage = errorExceptionMessage;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}

(3) JwtToken:

package com.shiro.jwt.dto;

import org.apache.shiro.authc.AuthenticationToken;

public class JwtToken implements AuthenticationToken {
    private static final long serialVersionUID = -8451637096112402805L;
    private String token;

    public JwtToken(String token) {
        this.token = token;
    }
    @Override
    public Object getPrincipal() {
        return token;
    }
    @Override
    public Object getCredentials() {
        return token;
    }
}

6、handler拦截器:

package com.shiro.jwt.handler;

import com.alibaba.fastjson.JSON;
import com.shiro.jwt.dto.CommonConstant;
import com.shiro.jwt.dto.CommonEnums;
import com.shiro.jwt.dto.JwtToken;
import com.shiro.jwt.dto.ResponseMessage;
import com.shiro.jwt.util.JwtUtil;
import com.shiro.jwt.util.RedisClient;
import org.apache.http.entity.ContentType;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.util.AntPathMatcher;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtFilter extends BasicHttpAuthenticationFilter {

    private static RedisClient redisClient;
    private AntPathMatcher antPathMatcher =new AntPathMatcher();
   /* static {
           //获取不到bean,报错spring context is null
        redisClient = ServiceFactory.getInstance().createRedisClient();
    }*/
    /**
     * 执行登录认证(判断请求头是否带上token)
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        System.out.println("JwtFilter-->>>isAccessAllowed-Method:init()");

        if (isLoginAttempt(request, response)) {
            return true;
        }

        try {
            //如果token校验不成功,则可能是执行登陆操作或是游客状态访问,校验该token是否为之前登录成功过的token
            executeLogin(request, response);
            return true;
        } catch (Exception e) {
            response.setContentType(ContentType.APPLICATION_JSON.toString());
            try {
                response.getWriter().write(JSON.toJSONString(ResponseMessage.error(CommonEnums.CODE_401.code,e.getMessage())));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }
    }

    /**
     * 判断用户是否是登入,检测headers里是否包含token字段
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        ServletContext servletContext = request.getServletContext();
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        redisClient = (RedisClient) context.getBean("redisClient");

        System.out.println("JwtFilter-->>>isLoginAttempt-Method:init()");
        HttpServletRequest req = (HttpServletRequest) request;
        if(antPathMatcher.match("/login",req.getRequestURI())){
            return true;
        }
        //前端带入的token
        String token = req.getHeader(CommonConstant.ACCESS_TOKEN);
        if (token == null) {
            return false;
        }
        //获取redis存储的token,redis存储token的key为CommonConstant.USER_TOKEN = "USER_TOKEN:{userAccount}"
        //所以需要获取userAccount,这里利用jwt从token反取
        String userAccount = JwtUtil.getUsername(token);
        String userToken = redisClient.get(CommonConstant.USER_TOKEN,userAccount);
        if(StringUtils.isEmpty(userToken)){
            return false;
        }
        if(!token.equals(userToken)){
            return false;
        }

        System.out.println("JwtFilter-->>>isLoginAttempt-Method:返回true");
        return true;
    }

    /**
     * 重写AuthenticatingFilter的executeLogin方法丶执行登陆操作
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("JwtFilter-->>>executeLogin-Method:init()");
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(CommonConstant.ACCESS_TOKEN);//Access-Token
        JwtToken jwtToken = new JwtToken(token);
        // 提交给realm进行登入,如果错误他会抛出异常并被捕获, 反之则代表登入成功,返回true
        getSubject(request, response).login(jwtToken);
        return true;
    }

    /**
     * 拦截器对跨域提供支持,否则前端访问接口进去拦截器异常导致访问失败
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("JwtFilter-->>>preHandle-Method:init()");
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,token, content-type"); //这里要加上content-type
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }
}

7、realm权限认证:

package com.shiro.jwt.realms;
import com.demo.dto.UserDTO;
import com.demo.service.UserService;
import com.shiro.jwt.dto.CommonConstant;
import com.shiro.jwt.dto.JwtToken;
import com.shiro.jwt.util.JwtUtil;
import com.shiro.jwt.util.RedisClient;
import org.apache.commons.lang.StringUtils;
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.springframework.beans.factory.annotation.Autowired;


public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisClient redisClient;
    /**
     * 必须重写此方法,不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 访问控制。比如某个用户是否具有某个操作的使用权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        UserDTO user  = (UserDTO) principalCollection.getPrimaryPrincipal();if (user == null) {
            System.out.println("授权失败,用户信息为空!!!");
            return null;
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 用户身份识别,非login方法进入
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //前端带入的token
        String token = (String) authenticationToken.getCredentials();// 校验token有效性
        //校验token
        //获取redis存储的token,redis存储token的key为CommonConstant.USER_TOKEN = "USER_TOKEN:{userAccount}"
        //所以需要获取userAccount,这里利用jwt从token反取
        String userAccount = JwtUtil.getUsername(token);
        String userToken = redisClient.get(CommonConstant.USER_TOKEN,userAccount);
        if(org.springframework.util.StringUtils.isEmpty(userToken)){
            throw new AuthenticationException("token已过期!");
        }
        if(!token.equals(userToken)){
            throw new AuthenticationException("token不匹配!");
        }

        String username = JwtUtil.getUsername(token);
        if (StringUtils.isEmpty(username)) {
            throw new AuthenticationException("token非法无效!");
        }// 查询用户信息
        UserDTO user = userService.findByUserName(username);
        if (user == null) {
            throw new AuthenticationException("用户不存在!");
        }// 判断用户状态
        return new SimpleAuthenticationInfo(user,token,getName());
    }
}

8、util:

(1)aes解密:

package com.shiro.jwt.util;


import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class AESUtils {

    private static String iv = "HGty&6%4ojyUyhgy";//偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量
    private static String Algorithm = "AES";
    private static String AlgorithmProvider = "AES/CBC/PKCS5Padding"; //算法/模式/补码方式
    public final static String key="FUjs@17654HGJKKn";

    public static byte[] generatorKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(Algorithm);
        keyGenerator.init(256);//默认128,获得无政策权限后可为192或256
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    public static IvParameterSpec getIv() throws UnsupportedEncodingException {
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
        System.out.println("偏移量:"+byteToHexString(ivParameterSpec.getIV()));
        return ivParameterSpec;
    }

    public static byte[] encrypt(String src, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
        return cipherBytes;
    }

    public static byte[] decrypt(String src, byte[] key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);

        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] hexBytes = hexStringToBytes(src);
        byte[] plainBytes = cipher.doFinal(hexBytes);
        return plainBytes;
    }

    /**
     * 解密
     * @param src
     * @param keyStr
     * @return
     * @throws Exception
     */
    public static String decryptStr(String src, String keyStr) throws Exception {

        byte key[] = keyStr.getBytes("utf-8");
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);

        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] hexBytes = hexStringToBytes(src);
        byte[] plainBytes = cipher.doFinal(hexBytes);
        return new String(plainBytes,"UTF-8");
    }


    public static String encrypt(String src, String keyStr) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {

        byte key[] = keyStr.getBytes("utf-8");
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
        return new String(cipherBytes,"UTF-8");
    }

    public static void main(String args[]){
        try {
            String passwordMd5 = MD5Util.MD5("123456");
            System.out.println("加密后密码:"+passwordMd5);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 将byte转换为16进制字符串
     * @param src
     * @return
     */
    public static String byteToHexString(byte[] src) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xff;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                sb.append("0");
            }
            sb.append(hv);
        }
        return sb.toString();
    }

    /**
     * 将16进制字符串装换为byte数组
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] b = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            b[i] = (byte) (charToByte(hexChars[pos]) << 4 | (charToByte(hexChars[pos + 1]))& 0xff);
        }
        return b;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


     /*public static void main(String[] args) {
        try {
            // byte key[] = generatorKey();
            System.out.println("FUjs@17654HGJKKn".length());
            // 密钥必须是16的倍数
            byte key[] = "FUjs@17654HGJKKn".getBytes("utf-8");//hexStringToBytes("0123456789ABCDEF");
            String src = "usersrs=111111?sdfjsalkj=1mlkjklasjdfkls?sss=sdfsjlk1123123123?sdd=453456465432165765432221351567897654132";
            System.out.println("密钥:"+byteToHexString(key));
            System.out.println("原字符串:"+src);

            String enc = byteToHexString(encrypt(src, key));
            System.out.println("加密:"+enc);
            System.out.println("解密:"+decryptStr(enc, AESUtils.key));
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/


}

(2) MD5:

package com.shiro.jwt.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class MD5Util {

    private final static Logger logger = LoggerFactory.getLogger(MD5Util.class);

    private final static String APP_KEY="hYHN#1son@16faEV2";
    private final static String CHARSET="UTF-8";
    /**
     * MD5加密算法
     *
     * @param s
     * @return
     */
    public final static String MD5(String s) throws NoSuchAlgorithmException {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'A', 'B', 'C', 'D', 'E', 'F' };
        byte[] btInput = s.getBytes();
        // 获得MD5摘要算法的 MessageDigest 对象
        MessageDigest mdInst;
        mdInst = MessageDigest.getInstance("MD5");
        // 使用指定的字节更新摘要
        mdInst.update(btInput);
        // 获得密文
        byte[] md = mdInst.digest();
        // 把密文转换成十六进制的字符串形式
        int j = md.length;
        char str[] = new char[j * 2];
        int k = 0;
        for (int i = 0; i < j; i++) {
            byte byte0 = md[i];
            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
            str[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
    }


    /**
     * 编码转换
     * @param content
     * @param charset
     * @return
     * @throws UnsupportedEncodingException
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    public static String sign(String prestr){
        String mysign = DigestUtils.md5Hex(getContentBytes(prestr + APP_KEY, CHARSET));
        return mysign;
    }

    public static String signParams(Map params){
        try {
            if (params != null && params.size()>0){
                List> list = new ArrayList(params.entrySet());
                Collections.sort(list, new Comparator>() {
                    @Override
                    public int compare(Map.Entry o1, Map.Entry o2) {
                        return o1.getKey().compareTo(o2.getKey());
                    }
                });
                StringBuffer sb = new StringBuffer();
                for (Map.Entry ent:list) {
                    sb.append(ent.getKey());
                    sb.append(ent.getValue());
                }
                logger.info("原字符串:{}",sb.toString());
                return sign(sb.toString());
            }
        }catch (Exception e){

        }
        return "";
    }

    public static boolean isSign(HashMap params,String sign){
        try{
            String newSign = signParams(params);
            logger.info("原签名:{}",sign);
            logger.info("新签名:{}",newSign);
            if (Objects.equals(sign,newSign)){
                return true;
            }
        }catch (Exception e){

        }
        return false;
    }



}

(3)redis操作:

package com.shiro.jwt.util;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Tuple;


@SuppressWarnings("unused")
@Component
public class RedisClient {
    private static boolean BORROW = true; // 在borrow一个事例时是否提前进行validate操作
    private static Logger logger = Logger.getLogger(RedisClient.class);
    @Autowired
    private JedisPool pool;


    /**
     * 获取连接
     */
    public  synchronized Jedis getJedis() {
        try {
            if (pool != null) {
                return pool.getResource();
            } else {
                return null;
            }
        } catch (Exception e) {
            logger.info("连接池连接异常");
            return null;
        }

    }




    /**
     * @Description: 关闭连接
     * @param @param jedis
     * @return void 返回类型
     */

    public static void getColse(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }


    /**
     * 格式化Key
     */
    public static String format(String formatKey, String... keyValues) {
        if (keyValues == null || keyValues.length == 0) {
            return formatKey;
        }
        StringBuilder key = new StringBuilder();
        char[] chars = formatKey.toCharArray();
        int index = -1;
        boolean inmark = false;
        boolean firstinmark = false;
        for (int i = 0; i < chars.length; i++) {
            char ch = chars[i];
            if (ch == '{') {
                index++;
                inmark = true;
                firstinmark = true;
            } else if (ch == '}') {
                inmark = false;
            } else if (inmark) {
                if (firstinmark) {
                    firstinmark = false;
                    key.append(keyValues[index]);
                }
            } else {
                key.append(chars[i]);
            }
        }
        return key.toString();
    }

    /********************************** 针对key的操作 **************************************/

    /**
     * 删除一个key
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 被删除的keys的数量
     */
    public Long del(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 查询一个key是否存在
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return key是否存在。
     */
    public boolean exists(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.exists(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 设置一个key的过期的秒数
     *
     * @param keyFormat
     *            key标识
     * @param seconds
     *            过期的秒数
     * @param keyValues
     *            key变量
     * @return 1表示设置成功, 0 表示设置失败或者无法被设置
     */
    public Long expire(String keyFormat, int seconds, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.expire(key, seconds);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 设置一个UNIX时间戳的过期时间
     *
     * @param keyFormat
     *            key标识
     * @param expireDate
     *            过期时间
     * @param keyValues
     *            key变量
     * @return 1表示设置成功, 0 表示设置失败或者无法被设置
     */
    public Long expireAt(String keyFormat, Date expireDate, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.pexpireAt(key, expireDate.getTime());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 移除给定key的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0 .
     */
    public Long persist(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.persist(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 设置一个key的过期的毫秒数
     *
     * 
     * 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
     * 
* * @param keyFormat * key标识 * @param milliSeconds * 过期的毫秒数 * @param keyValues * key变量 * @return 设置成功,返回 1,不存在或设置失败,返回 0 */ public Long pexpire(String keyFormat, long milliSeconds, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.pexpire(key, milliSeconds); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取key的有效毫秒数 * *
     * 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以毫秒为单位,返回 key * 的剩余生存时间。 */ public Long pttl(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.pttl(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取key的有效时间(单位:秒) * *
     * 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以秒为单位,返回 key * 的剩余生存时间。 */ public Long ttl(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.ttl(key); } finally { if (jedis != null) { jedis.close(); } } } /********************************** 针对字符串(string)的操作 **************************************/ /** * 追加一个值到key上 * *
     * 如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。
     * 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
     * 
* * @param keyFormat * key标识 * @param value * 要追加的值 * @param keyValues * key变量 * @return 返回append后字符串值(value)的长度。 */ public Long append(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.append(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 整数原子减1 * *
     * 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
     * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。
     * 这个操作最大支持在64位有符号的整型数字。
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 数字:减小之后的value */ public Long decr(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.decr(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 原子减指定的整数 * *
     * 将key对应的数字减decrement。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
     * 这个操作最多支持64位有符号的正型数字。
     * 
* * @param keyFormat * key标识 * @param integer * 要减小的数值 * @param keyValues * key变量 * @return 返回一个数字:减少之后的value值。 */ public Long decrby(String keyFormat, long integer, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.decrBy(key, integer); } finally { if (jedis != null) { jedis.close(); } } } /** * @param keyFormat * key标识 * @param keyValues * key变量 * @return key对应的value,或者null(key不存在时) */ public String get(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.get(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置一个key的value,并获取设置前的值 * *
     * 自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
     * exp:
     * GETSET可以和INCR一起使用实现支持重置的计数功能。
     * 举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。
     * 这可以通过GETSET mycounter "0"来实现:
     * 
* * @param keyFormat * key标识 * @param value * 要设置的值 * @param keyValues * key变量 * @return 设置之前的值 */ public String getSet(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.getSet(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 执行原子加1操作 * *
     * 对key对应的数字做加1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
     * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。这个操作最大支持在64位有符号的整型数字。
     * 提醒:这是一个string操作,因为Redis没有专用的数字类型。key对应的string都被解释成10进制64位有符号的整型来执行这个操作。
     * Redis会用相应的整数表示方法存储整数,所以对于表示数字的字符串,没必要为了用字符串表示整型存储做额外开销。
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 增加之后的value */ public Long incr(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.incr(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 执行原子加1操作,并且设置过期时间(单位:s) * *
     * 本操作是在{@linkplain RedisClient#incr(String, String...)}之上增加了一个设置过期时间的操作
     * 
* * @param keyFormat * key标识 * @param expireTime * 过期时间(单位:s) * @param keyValues * key变量 * @return 增加之后的value */ public Long incr(String keyFormat, int expireTime, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); long result = jedis.incr(key); jedis.expire(key, expireTime); return result; } finally { if (jedis != null) { jedis.close(); } } } /** * 执行原子增加一个整数 * *
     * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看方法{@linkplain RedisClient#incr(String, String...)}了解关于增减操作的额外信息。
     * 
* * @param keyFormat * key标识 * @param increment * 要增加的数值 * @param keyValues * key变量 * @return 增加后的value */ public Long incrBy(String keyFormat, long increment, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.incrBy(key, increment); } finally { if (jedis != null) { jedis.close(); } } } /** * 执行原子增加一个浮点数 * *
     * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
     * 
* * @param keyFormat * key标识 * @param increment * 要增加的数值 * @param keyValues * key变量 * @return 增加后的value */ public Double incrByFloat(String keyFormat, double increment, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.incrByFloat(key, increment); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置一个key的value值 * *
     * 警告:如果key已经存在了,它会被覆盖,而不管它是什么类型。
     * 
* * @param keyFormat * key标识 * @param value * 要设置的值 * @param keyValues * key变量 * * @return 总是"OK" */ public String set(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.set(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置key-value并设置过期时间(单位:秒) * *
     * 设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期。
     * 该命令相当于执行了{@link #set(String, String, String...) SET} + {@link #expire(String, int, String...) EXPIRE}.并且该操作是原子的
     * 
* * @param keyFormat * key标识 * @param seconds * 超时时间(单位:s) * @param value * 设置的值 * @param keyValues * key变量 * @return 状态码 */ public String setex(String keyFormat, int seconds, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.setex(key, seconds, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置key-value并设置过期时间(单位:毫秒) * *
     * 跟{@link #setex(String, int, String, String...)}效果差不多,唯一区别是超时时间是ms
     * 
* * @param keyFormat * key标识 * @param milliseconds * 超时时间(单位:ms) * @param value * 设置的值 * @param keyValues * key变量 * @return 状态码 */ public String psetex(String keyFormat, int milliseconds, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.psetex(key, (long) milliseconds, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置的一个关键的价值,只有当该键不存在 * *
     * 如果key不存在,就设置key对应字符串value。在这种情况下,该命令和SET一样。
     * 当key已经存在时,就不做任何操作。SETNX是"SET if Not eXists"。
     * 
* * @param keyFormat * key标识 * @param value * 设置的value * @param keyValues * key变量 * @return 1 如果key被set,0 如果key没有被set */ public Long setnx(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.setnx(key, value); } finally { if (jedis != null) { jedis.close(); } } } /********************************* Hash 操作 ******************************/ /** * 删除一个哈希域 * *
     * 从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。
     * 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0。
     * 
* * @param keyFormat * key标识 * @param field * 要删除的域 * @param keyValues * key变量 * @return 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域 */ public long hdel(String keyFormat, String field, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hdel(key, field); } finally { if (jedis != null) { jedis.close(); } } } /** * 删除一个hash中的多个域 * *
     * 相当于多次执行{@link #hdel(String, String, String...)}, 效率会有所提高
     * 
* * @param keyFormat * key标识 * @param fileds * 要删除的域 * @param keyValues * key变量 * * @return 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域 */ public Long hdel(String keyFormat, Set fileds, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hdel(key, fileds.toArray(new String[fileds.size()])); } finally { if (jedis != null) { jedis.close(); } } } /** * 判断给定域是否存在于哈希集中 * * @param keyFormat * key标识 * @param field * 指定的域 * @param keyValues * key变量 * @return 返回字段是否是 key 指定的哈希集中存在的字段。 */ public Boolean hexists(String keyFormat, String field, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hexists(key, field); } finally { if (jedis != null) { jedis.close(); } } } /** * 读取哈希域的的值 * * @param keyFormat * key标识 * @param field * 指定的域 * @param keyValues * key变量 * @return 该字段所关联的值。当字段不存在或者 key 不存在时返回null。 */ public String hget(String keyFormat, String field, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hget(key, field); } finally { if (jedis != null) { jedis.close(); } } } /** * 读取哈希域的的值(返回的是byte[]) * * @param keyFormat * key标识 * @param field * 指定的域 * @param keyValues * key变量 * @return 该字段所关联的值(byte[])。当字段不存在或者 key 不存在时返回null。 */ public byte[] hgetBytes(String keyFormat, String field, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hget(key.getBytes(), field.getBytes()); } finally { if (jedis != null) { jedis.close(); } } } /** * 从哈希集中读取全部的域和值 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 哈希集中字段和值的列表。当 key 指定的哈希集不存在时返回空列表。 */ public Map hgetAll(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hgetAll(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 将哈希集中指定域的值增加给定的数字 * *
     * 增加 key 指定的哈希集中指定字段的数值。
     * 如果 key 不存在,会创建一个新的哈希集并与 key 关联。
     * 如果字段不存在,则字段的值在该操作执行前被设置为 0
     * HINCRBY 支持的值的范围限定在 64位 有符号整数
     * 
* * @param keyFormat * key标识 * @param field * 指定的域 * @param value * 给定的数字 * @param keyValues * key变量 * @return 增值操作执行后的该字段的值。 */ public long hincrBy(String keyFormat, String field, long value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hincrBy(key, field, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 将哈希集中指定域的值增加给定的浮点数 * * @param keyFormat * key标识 * @param field * 指定的域 * @param value * 给定的浮点数 * @param keyValues * key变量 * @return 增值操作执行后的该字段的值。 */ public Double hincrByFloat(String keyFormat, String field, double value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hincrByFloat(key, field, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取hash的所有字段 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 哈希集中的字段列表,当 key 指定的哈希集不存在时返回空列表。 */ public Set hkeys(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hkeys(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取hash里所有字段的数量 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 哈希集中字段的数量,当 key 指定的哈希集不存在时返回 0 */ public Long hlen(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hlen(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 批量获取hash中的值 * *
     * 返回 key 指定的哈希集中指定字段的值。
     * 对于哈希集中不存在的每个字段,返回null值。
     * 因为不存在的keys被认为是一个空的哈希集,对一个不存在的 key 执行 HMGET 将返回一个只含有 null值的列表
     * 
* * @param keyFormat * key标识 * @param fileds * 指定的域 * @param keyValues * key变量 * @return 含有给定字段及其值的列表,并保持与请求相同的顺序。 */ public List hmget(String keyFormat, List fileds, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hmget(key, fileds.toArray(new String[fileds.size()])); } finally { if (jedis != null) { jedis.close(); } } } /** * 批量设置hash中的值 * *
     * 设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。
     * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联
     * 
* * @param keyFormat * key标识 * @param hash * 指定的域和值 * @param keyValues * key变量 * @return Return OK or Exception if hash is empty */ public String hmset(String keyFormat, Map hash, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hmset(key, hash); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置hash里面一个字段的值 * * @param keyFormat * key标识 * @param field * 字段 * @param value * 值 * @param keyValues * key变量 * @return 含义如下:1如果field是一个新的字段 0如果field原来在map里面已经存在 * */ public Long hset(String keyFormat, String field, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hset(key, field, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置hash里面一个字段的值(值为byte[]数组类型) * * @param keyFormat * key标识 * @param field * 字段 * @param value * 值 * @param keyValues * key变量 * @return 含义如下:1如果field是一个新的字段 0如果field原来在map里面已经存在 * */ public Long hset(String keyFormat, String field, byte[] value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hset(key.getBytes(), field.getBytes(), value); } finally { if (jedis != null) { jedis.close(); } } } /** * 设置hash的一个字段,只有当这个字段不存在时有效 * *
     * 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。
     * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。
     * 如果字段已存在,该操作无效果。
     * 
* * @param keyFormat * key标识 * @param field * 字段 * @param value * 值 * @param keyValues * key变量 * @return 1:如果字段是个新的字段,并成功赋值 0:如果哈希集中已存在该字段,没有操作被执行 */ public Long hsetnx(String keyFormat, String field, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hsetnx(key, field, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 获得hash的所有值 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 哈希集中的值的列表,当 key 指定的哈希集不存在时返回空列表。 */ public List hvals(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.hvals(key); } finally { if (jedis != null) { jedis.close(); } } } /******************************* SET 操作 *************************/ /** * 添加一个元素到集合(set)里 * *
     * 添加一个指定的member元素到集合的 key中.
     * 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
     * 如果key 的类型不是集合则返回错误.
     * 
* * @param keyFormat * key标识 * @param value * 元素 * @param keyValues * key变量 * @return 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素. */ public Long sadd(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.sadd(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 批量添加元素到集合(set)里 * *
     * 添加指定的member元素到集合的 key中.
     * 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
     * 如果key 的类型不是集合则返回错误.
     * 
* * @param keyFormat * key标识 * @param values * 要添加的元素集合 * @param keyValues * key变量 * @return 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素. */ public Long sadd(String keyFormat, List values, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.sadd(key, values.toArray(new String[values.size()])); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取集合里面的元素数量 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 集合的基数(元素的数量),如果key不存在,则返回 0. */ public Long scard(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.scard(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 确定一个给定的值是一个集合的成员 * * @param keyFormat * key标识 * @param value * 给定的值 * @param keyValues * key变量 * @return 返回成员 value是否是存储的集合 key的成员. */ public Boolean sismember(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.sismember(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取集合里面的所有key * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 集合中的所有元素. */ public Set smembers(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.smembers(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 删除并获取一个集合里面的元素 * *
     * 移除并返回一个集合中的随机元素
     * 该命令与 {@link #srandmember(String, String...)}相似,不同的是srandmember命令返回一个随机元素但是不移除.
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 被移除的元素, 当key不存在的时候返回 null . */ public String spop(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.spop(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 从集合里面随机获取一个key * *
     *  随机返回key集合中的一个元素.
     *  该命令作用类似于{@link #spop(String, String...)}命令,
     *  不同的是SPOP命令会将被选择的随机元素从集合中移除, 而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
     * 
* * @param keyFormat * key标识 * @param keyValues * key变量 * @return 被移除的元素, 当key不存在的时候返回 null . */ public String srandmember(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.srandmember(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 从集合里删除一个元素 * * @param keyFormat * key标识 * @param member * 要删除的元素 * @param keyValues * key变量 * @return 从集合中移除元素的个数,不包括不存在的成员. */ public Long srem(String keyFormat, String member, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.srem(key, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 批量从集合里删除元素 * * @param keyFormat * key标识 * @param members * 要删除的元素 * @param keyValues * key变量 * @return 从集合中移除元素的个数,不包括不存在的成员. */ public Long srem(String keyFormat, List members, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.srem(key, members.toArray(new String[members.size()])); } finally { if (jedis != null) { jedis.close(); } } } /***************************** ZSET 操作 *****************************/ /** * 添加到有序set的一个成员,如果它已经存在,则更新分数。 * * @param keyFormat * key标识 * @param member * 成员 * @param score * 分值 * @param keyValues * key变量 * @return 如果是新添加的,返回1,如果是更新,返回0 */ public Long zadd(String keyFormat, String member, double score, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zadd(key, score, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 批量添加到有序的成员,如果已经存在,则更新分数。 * * @param keyFormat * key标识 * @param scoreMembers * 成员和对应的分值 * @param keyValues * key变量 * @return 返回添加到有序集合中元素的个数,不包括那种已经存在只是更新分数的元素。 */ public Long zadd(String keyFormat, Map scoreMembers, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zadd(key, scoreMembers); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取一个排序的集合中的成员数量 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return key存在的时候,返回有序集的元素个数,否则返回0。 */ public Long zcard(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zcard(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取给定值范围内的成员数 * *
     * 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。
     * 关于参数min和max的详细使用方法,请参考ZRANGEBYSCORE命令。
     * 
* * @param keyFormat * key标识 * @param min * 范围下限 * @param max * 范围上限 * @param keyValues * key变量 * @return key存在的时候,返回有序集的元素个数,否则返回0。 */ public Long zcount(String keyFormat, double min, double max, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zcount(key, min, max); } finally { if (jedis != null) { jedis.close(); } } } /** * 给一个有序集合中的成员增加指定的分值 * *
     * 为有序集key的成员member的分值值加上score。如果key中不存在member,就在key中添加一个member,分值是score
     * 如果key不存在,就创建一个只含有指定member成员的有序集合。
     * 当key不是有序集类型时,返回一个错误。
     * 
* * @param keyFormat * key标识 * @param member * 成员 * @param score * 增加的分值 * @param keyValues * key变量 * @return member成员的新分值。 */ public Double zincrby(String keyFormat, String member, double score, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zincrby(key, score, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取排名在[start, end]之间的成员 * *
     * 返回有序集key中,指定区间内的成员。其中成员按score值递增(从小到大)来排序。具有相同score值的成员按字典序来排列。
     * 如果你需要成员按score值递减(score相等时按字典序递减)来排列,请使用ZREVRANGE命令。
     * 下标参数start和stop都以0为底,也就是说,以0表示有序集第一个成员,以1表示有序集第二个成员,以此类推。
     * 你也可以使用负数下标,以-1表示最后一个成员,-2表示倒数第二个成员,以此类推。
     * 超出范围的下标并不会引起错误。如果start的值比有序集的最大下标还要大,或是start > stop时,ZRANGE命令只是简单地返回一个空列表。
     * 另一方面,假如stop参数的值比有序集的最大下标还要大,那么Redis将stop当作最大下标来处理。
     * 
* * @param keyFormat * key标识 * @param start * 排名开始 * @param end * 排名结尾 * @param keyValues * key变量 * @return 排名在[start, end]之间的成员 */ public Set zrange(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrange(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取排名在[start, end]之间的成员及分数 * *
     * 该方法和{@link #zrange(String, long, long, String...)}相似,只是连带分数值一起返回
     * 
* * @param keyFormat * key标识 * @param start * 排名开始 * @param end * 排名结尾 * @param keyValues * key变量 * @return 排名在[start, end]之间的成员及分数 * @see #zrange(String, long, long, String...) */ public Set zrangeWithScores(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrangeWithScores(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取分数值在[min, max]之间的成员 * * @param keyFormat * key标识 * @param min * 最小分值 * @param max * 最大分值 * @param keyValues * keyValues key变量 * @return 分值在[min, max]之间的成员 */ public Set zrangeByScore(String keyFormat, double min, double max, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrangeByScore(key, min, max); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取分数值在[min, max]之间的成员及分数 * * @param keyFormat * key标识 * @param min * 最小分值 * @param max * 最大分值 * @param keyValues * keyValues key变量 * @return 分值在[min, max]之间的成员及分数 */ public Set zrangeByScoreWithScores(String keyFormat, double min, double max, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrangeByScoreWithScores(key, min, max); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取有序集合中某个成员的排名(从0开始) * *
     * 返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。
     * 排名以0为底,也就是说,score值最小的成员排名为0。
     * 使用ZREVRANK命令可以获得成员按score值递减(从大到小)排列的排名。
     * 
* * @param keyFormat * key标识 * @param member * 指定的成员 * @param keyValues * key变量 * @return 该元素的排名,如果集合中不存在该元素,返回null */ public Long zrank(String keyFormat, String member, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrank(key, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 从排序的集合中删除一个成员 * * @param keyFormat * key标识 * @param member * 要删除的成员 * @param keyValues * key变量 * @return 删除成功返回1,如果集合中不存在返回0 */ public Long zrem(String keyFormat, String member, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrem(key, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 删除排名在[start,end](从小到大)之间的成员 * * @param keyFormat * key标识 * @param start * 排名的开始 * @param end * 排名的结尾 * @param keyValues * key变量 * @return 被移除成员的数量。 */ public Long zremrangeByRank(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zremrangeByRank(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } /** * 删除分数值在[min,max]之间的成员 * * @param keyFormat * key标识 * @param min * 最小分数值 * @param max * 最大分数值 * @param keyValues * key变量 * @return 被移除成员的数量。 */ public Long zremrangeByScore(String keyFormat, double min, double max, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zremrangeByScore(key, min, max); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取排名在[start, end](从大到小)之间的成员 * *
     * 返回有序集key中,指定区间内的成员。
     * 其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。
     * 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
     * 
* * @param keyFormat * key标识 * @param start * 排名开始 * @param end * 排名结束 * @param keyValues * key变量 * @return 取排名在[start, end](从大到小)之间的成员 */ public Set zrevrange(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrevrange(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取排名在[start, end](从大到小)之间的成员及分数值 * *
     * 返回有序集key中,指定区间内的成员。
     * 其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。
     * 除了成员按score值递减的次序排列这一点外,ZREVRANGEWITHSCORE命令的其他方面和ZRANGEWITHSCORE命令一样。
     * 
* * @param keyFormat * key标识 * @param start * 排名开始 * @param end * 排名结束 * @param keyValues * key变量 * @return 排名在[start, end](从大到小)之间的成员及分数值 */ public Set zrevrangeWithScores(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrevrangeWithScores(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } /** * 获得成员按 score 值递减(从大到小)排列的排名 * * @param keyFormat * key标识 * @param member * 成员 * @param keyValues * key变量 * @return 成员的排名 */ public Long zrevrank(String keyFormat, String member, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrevrank(key, member); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取分数值在[max, min](从大到小)之间的成员 * * @param keyFormat * key标识 * @param max * 最大分数值 * @param min * 最小分数值 * @param keyValues * key变量 * @return 分数值在[max, min](从大到小)之间的成员 */ public Set zrevrangeByScore(String keyFormat, double max, double min, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zrevrangeByScore(key, max, min); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取成员在有序集合中的分数值 * * @param keyFormat * key标识 * @param member * 成员 * @param keyValues * key变量 * @return member成员的score值,如果member元素不是有序集key的成员,或key不存在,返回null。 */ public Double zscore(String keyFormat, String member, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.zscore(key, member); } finally { if (jedis != null) { jedis.close(); } } } /***************************** LIST 操作 *************************************/ /** * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用 * *
     * 该操作是从left 到 right获取第一个元素
     * 
* * @param keyFormat * key标识 * @param timeout * 指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。 * @param keyValues * key变量 * @return 如果阻塞超时还没有获取值,则返回空(列表)。如果有值则返回一个List,第一个值表示key名称,第二个元素为value */ public List blpop(String keyFormat, int timeout, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.blpop(timeout, key); } finally { if (jedis != null) { jedis.close(); } } } /** * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用 * *
     * 该操作是从right 到 left获取第一个元素
     * 
* * @param keyFormat * key标识 * @param timeout * 指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。 * @param keyValues * key变量 * @return 如果阻塞超时还没有获取值,则返回空(列表)。如果有值则返回一个List,第一个值表示key名称,第二个元素为value */ public List brpop(String keyFormat, int timeout, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.brpop(timeout, key); } finally { if (jedis != null) { jedis.close(); } } } /** * 获得队列(List)的长度 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return list长度 */ public Long llen(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.llen(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的左边出队一个元素 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 返回第一个元素的值,或者当 key 不存在时返回 null。 */ public String lpop(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.lpop(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的左边入队一个元素 * * @param keyFormat * key标识 * @param value * 元素值 * @param keyValues * key变量 * @return 在 push 操作后的 list 长度。 */ public Long lpush(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.lpush(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的左边入队多个元素 * * @param keyFormat * key标识 * @param values * 元素值列表 * @param keyValues * key变量 * @return 在 push 操作后的 list 长度。 */ public Long lpush(String keyFormat, List values, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.lpush(key, values.toArray(new String[values.size()])); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的右边入队一个元素 * * @param keyFormat * key标识 * @param value * 元素值 * @param keyValues * key变量 * @return 在 push 操作后的 list 长度。 */ public Long rpush(String keyFormat, String value, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.rpush(key, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的右边入队多个元素 * * @param keyFormat * key标识 * @param values * 元素值列表 * @param keyValues * key变量 * @return 在 push 操作后的 list 长度。 */ public Long rpush(String keyFormat, List values, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.rpush(key, values.toArray(new String[values.size()])); } finally { if (jedis != null) { jedis.close(); } } } /** * 从队列的右边出队一个元素 * * @param keyFormat * key标识 * @param keyValues * key变量 * @return 返回第一个元素的值,或者当 key 不存在时返回 null。 */ public String rpop(String keyFormat, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.rpop(key); } finally { if (jedis != null) { jedis.close(); } } } /** * 从列表中获取指定返回的元素 * *
     * 返回存储在 key 的列表里指定范围内的元素。
     * start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。
     * 偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。
     * 
* * @param keyFormat * key标识 * @param start * 开始偏移量 * @param end * 结束偏移量 * @param keyValues * key变量 * @return */ public List lrange(String keyFormat, long start, long end, String... keyValues) { String key = format(keyFormat, keyValues); Jedis jedis = null; try { jedis = getJedis(); return jedis.lrange(key, start, end); } finally { if (jedis != null) { jedis.close(); } } } // /** // * 使用管道进行批量的操作 // * // * @param keyFormat // * key标识 // * @param executeInPipeline // * 批量执行的回调 // */ // public void pipelined(String keyFormat, ExecuteInPipeline executeInPipeline) { // Jedis jedis = null; // try { // jedis = getJedis(); // Pipeline pipeline = jedis.pipelined(); // executeInPipeline.execute(pipeline); // } finally { // if (jedis != null) { // jedis.close(); // } // } // } // // public String getConfigFile() { // return configFile; // } // public void setConfigFile(String configFile) { // this.configFile = configFile; // } }

 (4)JWT:

package com.shiro.jwt.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.shiro.jwt.dto.CommonConstant;
import com.shiro.jwt.factory.ServiceFactory;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

public class JwtUtil {

    private static  RedisClient redisClient;

      static {

        redisClient = ServiceFactory.getInstance().createRedisClient();
      }

    /**
     * 校验token是否正确
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     * @return token中包含的用户名
     */
    public static String getUsername( HttpServletRequest req) {
        try {
            String token =  req.getHeader(CommonConstant.ACCESS_TOKEN);
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    public static String getUsername( String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,5min(分钟)后过期
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        //多点登陆,单一点登陆去掉此段代码,每次登录生成新的token
        String redisToken = redisClient.get(CommonConstant.USER_TOKEN, username);
        if(StringUtils.isNotEmpty(redisToken)){
            return redisToken;
        }

        Date date = new Date(System.currentTimeMillis() + CommonConstant.EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create()
                .withClaim("username", username)
                .withExpiresAt(date)
                .sign(algorithm);
    }
}

9、controller:

(1)IndexController:

package com.shiro.jwt.controller;

import com.demo.dto.UserDTO;
import com.demo.service.UserService;
import com.shiro.jwt.dto.CommonConstant;
import com.shiro.jwt.dto.ResponseMessage;
import com.shiro.jwt.util.AESUtils;
import com.shiro.jwt.util.JwtUtil;
import com.shiro.jwt.util.MD5Util;
import com.shiro.jwt.util.RedisClient;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class IndexController {

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/login")
    public ResponseMessage login(@RequestBody UserDTO user, HttpSession session){
        String username = user.getUserName();
        String passwordRsa = user.getPassword();
        //明文密码
        String password = null;
        //md5加密后的密码
        String md5Password = null;
        try {
            password = AESUtils.decryptStr(passwordRsa,AESUtils.key);
            md5Password = MD5Util.MD5(password);
        } catch (Exception e) {
            throw new IncorrectCredentialsException();
        }
        //判断密码是否正确
        UserDTO dbUser = userService.findByUserName(username);
        if(!dbUser.getPassword().equals(md5Password)){
            return ResponseMessage.error("用户名或密码错误");
        }

        // 认证成功,返回token
        String token = JwtUtil.sign(username, password);
        redisClient.setex(CommonConstant.USER_TOKEN,CommonConstant.EXPIRE_TIME / 1000,
                username,token);
        return ResponseMessage.success("登录成功",token);
    }

}

(2):

package com.shiro.jwt.controller;

import com.shiro.jwt.dto.ResponseMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Random;

@RestController
@RequestMapping("/code")
public class CodeController {

    private static Logger logger = LoggerFactory.getLogger(CodeController.class);

    /**
     * 获取验证码
     */
    @GetMapping(value = "/getCode")
    public ResponseMessage images(HttpServletRequest request, HttpServletResponse response) {

        try {
            HttpSession httpSession = request.getSession();
            Random r = new Random();
            String code = String.valueOf(r.nextInt(100));
            httpSession.setAttribute("code",code);
            return ResponseMessage.success("验证码",code);
        } catch (Exception e) {
            logger.error("ValidateCodeController images ERROR MESSAGE={}", e.getMessage(), e);
        }
        return ResponseMessage.error("");
    }
}

(3)

package com.shiro.jwt.controller;


import com.demo.dto.AuthorityDTO;
import com.demo.dto.UserDTO;
import com.demo.dto.UserQueryDTO;
import com.demo.service.UserService;
import com.github.pagehelper.PageInfo;
import com.shiro.jwt.dto.CommonConstant;
import com.shiro.jwt.dto.CommonEnums;
import com.shiro.jwt.dto.ResponseMessage;
import com.shiro.jwt.util.JwtUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@RequestMapping("/user")
@RestController
public class UserController {

    @Autowired
    private UserService userService;


    /**
     * 获取所有用户
     * @return
     */
    @RequestMapping("/getAllUsers")
    public ResponseMessage getAllUsers(){
        List  users = userService.getAllUsers();
        return ResponseMessage.success(users);
    }


    /**
     * 获取分页用户
     * @return
     */
    @RequestMapping("/getPagerUser")
    public ResponseMessage getPagerUser(@RequestBody UserQueryDTO userQueryDTO){
        PageInfo users = userService.getPagerUser(userQueryDTO);
        return ResponseMessage.success(users);
    }

    /**
     * 获取权限
     */
    @RequestMapping("/getMyAuthorities")
    public ResponseMessage  getMyAuthorities(HttpServletRequest req){
        String userAccount = JwtUtil.getUsername(req);
        UserDTO user = userService.findByUserName(userAccount);
        Integer currentUserId = user.getId();
        List authorityDTOS= userService.getAuthortiesByUserId(currentUserId);
        return ResponseMessage.success(authorityDTOS);
    }

    @GetMapping(value = "/logout")
    public ResponseMessage logout(HttpServletRequest request) {
        try{
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
        }catch (Exception e){
            //logger.error("登出失败:", e);
        }
        return ResponseMessage.success(CommonEnums.CODE_200.code,CommonEnums.CODE_200.message);
    }

    /**
     * 获取
     */
    @RequestMapping("/getCurrentUser")
    public ResponseMessage  getCurrentUser(HttpServletRequest req){
        String userAccount = JwtUtil.getUsername(req);
        return ResponseMessage.success(userAccount);
    }
}

10、factory:注入springcontext:

package com.shiro.jwt.factory;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


@Component
public class ApplicationContextRegister implements ApplicationContextAware {
    private static Logger logger = LoggerFactory.getLogger(ApplicationContextRegister.class);
    private static ApplicationContext APPLICATION_CONTEXT;
    /**
     * 设置spring上下文
     * @param applicationContext spring上下文
     * @throws BeansException
     * */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        logger.debug("ApplicationContext registed-->{}", applicationContext);
        DefaultBeanFactory.setSpringApplicationContext(applicationContext);
        APPLICATION_CONTEXT = applicationContext;
    }

    /**
     * 获取容器
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return APPLICATION_CONTEXT;
    }

    /**
     * 获取容器对象
     * @param type
     * @param 
     * @return
     */
    public static  T getBean(Class type) {
        return APPLICATION_CONTEXT.getBean(type);
    }
}

 

package com.shiro.jwt.factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class DefaultBeanFactory {
	private static ApplicationContext context = null;
	private static DefaultBeanFactory instance = null;
	private static Object lock = new Object();

	private DefaultBeanFactory(String filepath){
		try {
			context = new ClassPathXmlApplicationContext(filepath);
		} catch (Exception e) {
		}
	}
	@SuppressWarnings("static-access")
	private DefaultBeanFactory(ApplicationContext context){
		try {
			this.context = context;
		} catch (Exception e) {
		}
	}

	public static void setSpringApplicationContext(ApplicationContext context){
		synchronized (lock) {
			instance = new DefaultBeanFactory(context);
		}
	}
	public static DefaultBeanFactory getInstance() {
		if(instance == null || context == null){
			throw new RuntimeException("Spring context is null!");
		}
		return instance;
	}

	public static DefaultBeanFactory getInstance(String filepath) {
		synchronized (lock) {
			instance = new DefaultBeanFactory(filepath);
		}
		return instance;
	}
	public Object getBean(String name) {
		return context.getBean(name);
	}
}

获取beanutil:

package com.shiro.jwt.factory;

import com.shiro.jwt.util.RedisClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ServiceFactory {


    private static Logger logger = LoggerFactory.getLogger(ServiceFactory.class);

    private static ServiceFactory instance = new ServiceFactory();

    private final String REDIS_CLIENT_BEAN="redisClient";

    private final String USER_ACTION_LOG_SERVICE = "userActionLogService";


    public ServiceFactory() {
        // TODO Auto-generated constructor stub
    }

    public static ServiceFactory getInstance() {
        if (instance == null) {
            instance = new ServiceFactory();
        }
        return instance;
    }

    public RedisClient createRedisClient() {
        try {
            return (RedisClient) DefaultBeanFactory.getInstance().getBean(REDIS_CLIENT_BEAN);
        } catch (Exception e) {
            throw new RuntimeException("创建 createRedisClient BEAN 异常", e);
        }
    }


}

 

二、测试:

1、登录前调用接口:

springboot+shiro(JWT管理)(一)简单实例_第3张图片

2、登录前调用获取验证码接口:

springboot+shiro(JWT管理)(一)简单实例_第4张图片

3、登录:

springboot+shiro(JWT管理)(一)简单实例_第5张图片 4、登录后再获取用户:

springboot+shiro(JWT管理)(一)简单实例_第6张图片

5、再次登录:

springboot+shiro(JWT管理)(一)简单实例_第7张图片

6、使用第一次登录的token获取数据,获取成功:

springboot+shiro(JWT管理)(一)简单实例_第8张图片

你可能感兴趣的:(springboot+shiro(JWT管理)(一)简单实例)