spring+springMvc+mybatis+maven+valid+redis+jwt 初始框架搭建、返回值包装、登录拦截等

仅作为记录,如有不妥,烦请大佬指出。

一:pom文件的引入,将框架所用到的jar包导入进来,刷新maven工程

注意:亲测所有依赖版本均兼容

创建时首先要注意是否版本兼容,因为如果不兼容,启动项目时可能会报一些错误(笔者踩过许多坑)

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>

  <!--spring 配置文件创建-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>

  <!--阿里json包-->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
  </dependency>

  <!--spring 核心-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.7.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.7.RELEASE</version>
    <type>jar</type>
    <scope>compile</scope>
  </dependency>

  <!--mybatis核心-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.3</version>
  </dependency>

  <!--mysql相关包-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
  </dependency>

  <!-- 数据库连接池-druid方式 -->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
  </dependency>

  <!--aop相关包-->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.5</version>
</dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.5</version>
  </dependency>

  <!--日志相关包-->
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.25</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
  </dependency>
  <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
  </dependency>
  <dependency>
    <groupId>org.logback-extensions</groupId>
    <artifactId>logback-ext-spring</artifactId>
    <version>0.1.5</version>
  </dependency>


  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.10</version>
  </dependency>

  <!--lombok相关包-->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>RELEASE</version>
    <scope>compile</scope>
  </dependency>

  <!--json-->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.10.2</version>
  </dependency>

  <!-- 添加<scope>provided</scope>,因为provided表明该包只在编译和测试的时候用,所以,当启动tomcat的时候,就不会冲突了,完整依赖如下-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
    <version>4.0.1</version>
  </dependency>

  <!--hibernate的vail框架-->
  <dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.0.Alpha1</version>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.1.Final</version>
  </dependency>

  <!-- jwt依赖包 -->
  <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
  </dependency>
  <dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
  </dependency>

  <!-- redis依赖 -->
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.7.1</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.6.2.RELEASE</version>
  </dependency>
</dependencies>

二:创建spring所需的配置文件,这里我们命名为applicationContext(spring配置内容上下文):包含配置业务层(service)的扫描、redis配置文件、myatis配置文件、和mybatis配置文件中所需的配置器交给spring容器管理

1.配置扫描器,扫描service是具体将service业务层都交给spring容器去管理

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

    <!--配置扫描器 扫描service业务层-->
    <context:component-scan base-package="com.atdp.dpinfo.service"/>

    <!--资源属性的配置器,将BeanFactory的里定义的内容放在一个以.propertis后缀的文件中,将上下文(配置文 件)中的属性值放在另一个单独的标准java Properties文件中去-->
    <bean id="configurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
        <property name="locations">
            <list>
                <!--将配置文件引入-->
                <value>classpath:config.properties</value>
                <value>classpath:redis.properties</value>
            </list>
        </property>
        <property name="fileEncoding" value="UTF-8"></property>
    </bean>

    <!-- 使用annotation 自动注册bean,并保证@Required,@Autowired的属性被注入 -->
    <context:component-scan base-package="com.atdp.dpinfo.service">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- spring 注解 扫描除了Controller之外的其他组件 -->
    <context:annotation-config/>
    <context:component-scan base-package="com.atdp.dpinfo.common.jwt"/>
    <!-- aop注解注入 -->
<!--    <aop:aspectj-autoproxy/>-->

    <!--扫面mybatis,将mybatis整合到spring中-->
    <import resource="spring-mybatis.xml"/>

    <!--引入redis,扫描redis-->
    <import resource="applicationContext-redis.xml"/>
</beans>

三:创建数据库连接池配置,因我们是测试阶段,并没有生产环境和开发环境之分,所以只创建config.properties,如果区分环境的,可多次创建此配置文件

注:需注意格式

#JDBC
jdbc.driver= com.mysql.cj.jdbc.Driver
jdbc.url= jdbc:mysql://xxxxxxxx:33xx/xxxxx?useSSL=true
jdbc.username= xxx
jdbc.password= xxxxxxxx
#\u5B9A\u4E49\u521D\u59CB\u8FDE\u63A5\u6570
jdbc.initialSize=0
#\u5B9A\u4E49\u6700\u5927\u8FDE\u63A5\u6570
jdbc.maxActive=20
#\u5B9A\u4E49\u6700\u5927\u7A7A\u95F2
jdbc.maxIdle=20
#\u5B9A\u4E49\u6700\u5C0F\u7A7A\u95F2
jdbc.minIdle=1
#\u5B9A\u4E49\u6700\u957F\u7B49\u5F85\u65F6\u95F4
jdbc.maxWait=60000

四:创建mybatis配置文件,因都是交给spring整合的,命名为spring-mybatis:

1.将交给spring容器管理的连接池内容拿进

2.结合spring和mybatis,扫描mapper层中所有类

3.配置DAO接口所在包名,Spring会自动查找其下的类

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

    <!-- 连接池 -->
    <bean id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method = "close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}" />
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <!-- 连接池最大空闲 -->
<!--        <property name="maxa" value="${jdbc.maxIdle}" />-->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${jdbc.minIdle}" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${jdbc.maxWait}" />
    </bean>

    <!-- 结合Spring和Mybatis -->
    <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件 -->
        <property name = "mapperLocations" value="classpath:mapper/*.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean class = "org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name = "basePackage" value="com.atdp.dpinfo.mapper" />
        <property name = "sqlSessionFactoryBeanName" value = "sqlSessionFactory" />
    </bean>

    <!-- 定义事务 -->
    <bean id = "transactionManager"
          class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name = "dataSource" ref = "dataSource" />
    </bean>

<!--    <configuration>-->
<!--        <settings>-->
<!--            <setting name="mapUnderscoreToCamelCase" value="true"/>-->
<!--        </settings>-->
<!--    </configuration>-->
    <!-- 使用注解定义事务 -->
    <tx:annotation-driven transaction-manager = "transactionManager" />
</beans>

五:创建springMvc配置文件

1.首先配置扫描器,扫描controller层

2.配置拦截器,将创建的拦截类引入,每当访问时,加载此类

3.将映射出的结果赋予格式,这里我们使用的json

4.注册全局异常处理类,如有异常,先用此类拦截然后输出错误结果

5.引入hibernate的vaild框架

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


    <!--配置扫描器 扫描controller-->
    <context:component-scan base-package="com.atdp.dpinfo.controller">
    </context:component-scan>
        <aop:aspectj-autoproxy proxy-target-class="true">
    </aop:aspectj-autoproxy>

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!-- 允许跨域 -->
<!--        <mvc:interceptor>-->
<!--            <mvc:mapping path="/**"/>-->
<!--            <bean class="com.atdp.dpinfo.common.jwt.HttpInterceptor"></bean>-->
<!--        </mvc:interceptor>-->
        <!-- 检验Token -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.atdp.dpinfo.common.jwt.HeaderTokenInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <!-- 开启对Spring MVC高级功能的支持 例如: JSR303校验 映射动态请求 ... -->
    <!--如不此注解 将不会正常返回json-->
    <mvc:annotation-driven conversion-service="conversionServiceFactoryBean">
        <mvc:message-converters>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <!-- MediaTypes -->
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json</value>
                    </list>
                </property>
                <!-- FastJsonConfig -->
                <property name="fastJsonConfig" ref="fastJsonConfig" />
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
        <!--默认编码格式 -->
        <property name="charset" value="UTF-8"/>

        <property name="serializerFeatures">
            <list>
                <value>WriteMapNullValue</value>
            </list>
        </property>
    </bean>

    <!-- 使用fastJson来支持JSON数据格式 -->
    <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
                <value>application/json</value>
            </list>
        </property>
        <property name="features">
            <list>
                <value>WriteMapNullValue</value>
                <value>QuoteFieldNames</value>
            </list>
        </property>
    </bean>

    <!-- 注册全局异常处理器 -->
    <bean class="com.atdp.dpinfo.common.exception.GloblaException"/>

    <!--配置自定义类型转换器-->
    <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.atdp.dpinfo.common.mvc.StringToDateConverter"/>
            </set>
        </property>
    </bean>

    <!--hibernate的vail bean级别校验-->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!--注入hibernate的验证器-->
        <property name="providerClass"  value="org.hibernate.validator.HibernateValidator"/>
    </bean>

    <!--方法级别的校验 要校验的方法所在类必须添加@Validated注解-->
    <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
        <!-- 可以引用自己的 validator 配置,在本文中(下面)可以找到 validator 的参考配置,如果不指定则系统使用默认的 -->
        <property name="validator" ref="validator" />
    </bean>
</beans>

六:创建redis属性

redis.host=127.0.0.1
redis.port=6379
#redis.password=123456
#最大空闲数(默认:8)
redis.maxIdle=300
#当连接池资源耗尽时,调用者最大阻塞时间,超时将抛出异常.单位:毫秒,默认:-1,表示永不超时.
redis.maxWaitMillis=1000
#最大连接数(默认:8)
redis.maxTotal=500
#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 (默认:false)
redis.testOnBorrow=true
redis.testOnReturn=true
redis.testWhileIdle=true
redis.blockWhenExhausted=false
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.minEvictableIdleTimeMillis=1800000

七:结合spring-redis,创建文件

1.扫描redis属性文件

2.将连接池设置

3.配置redis的工具类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--扫描redis配置文件-->
<!--    <context:property-placeholder ignore-unresolvable="true" location="classpath:redis.properties"/>-->

    <!--设置连接池-->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <!-- 最大连接数 -->
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
        <property name="testOnReturn" value="${redis.testOnReturn}" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="${redis.testWhileIdle}" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="${redis.blockWhenExhausted}" />
    </bean>
    <!--Spring整合Jedis,设置连接属性-->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:hostName="${redis.host}"
          p:port="${redis.port}"
          p:pool-config-ref="poolConfig"
          p:timeout="100000"/>

    <bean id="redisTemplate"
          class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
        <!-- 如果不配置Serializer,那么存储的时候只能使用String,如果用对象类型存储,那么会提示错误 can't cast to String!!!-->
        <property name="keySerializer">
            <!--对key的默认序列化器。默认值是StringSerializer-->
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <!--是对value的默认序列化器,默认值是取自DefaultSerializer的JdkSerializationRedisSerializer。-->
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
        <!--存储Map时key需要的序列化配置-->
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <!--存储Map时value需要的序列化配置-->
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
    </bean>
    <!--配置redis工具类bean-->
    <bean id="redisUtils" class="com.atdp.dpinfo.common.redis.RedisUtil"></bean>
</beans>

八:logback文件创建,更改控制台打印内容,设置自己喜欢的颜色

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <property resource="config.properties" />

    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)</Pattern>
        </encoder>
    </appender>

    <!-- 文件输出 - 全部日志 -->
    <appender name="file.all" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.output.dir}/all.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.output.dir}/archive/%d{yyyy-MM-dd}_all.tar.gz</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] [%thread] %logger{50}#%method:%L %msg%n</Pattern>
            <charset>UTF-8</charset>
        </encoder>

    </appender>

    <!-- 文件输出 - 访问日志 -->
    <appender name="file.access" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.output.dir}/access.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.output.dir}/archive/%d{yyyy-MM-dd}_access.log.gz</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%msg%n</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 文件输出 - 定时任务执行日志 -->
    <appender name="file.timedtask" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.output.dir}/timedtask.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.output.dir}/archive/%d{yyyy-MM-dd}_timedtask.tar.gz</FileNamePattern>
            <maxHistory>3</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger{50}#%method:%L %msg%n</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--sql日志输出-->
    <logger name="org.springframework.web.servlet.DispatcherServlet" level="TRACE" additivity="true"/>
    <logger name="org.apache.ibatis" level="DEBUG" additivity="true"/>
    <logger name="java.sql.Connection" level="DEBUG" additivity="true"/>
    <logger name="java.sql.Statement" level="DEBUG" additivity="true"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG" additivity="true"/>

    <root level="${log.level.root}">
        <appender-ref ref="console" />
        <appender-ref ref="file.all" />
        <appender-ref ref="file.timedtask" />
    </root>

</configuration>

九:最为关键的一步,修改web.xml

1.将前几步创建的配置文件加载到此xml中

2.设置编码过滤器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <display-name>Archetype Created Web Application</display-name>

    <!--spring容器加载-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!--日志文件加载-->
    <context-param>
        <param-name>logbackConfigLocation</param-name>
        <param-value>classpath:logback.xml</param-value>
    </context-param>

    <!-- 编码过滤器 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--spring监听器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- SpringMVC的前端控制器 -->
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- SpringMVCp配置文件路径 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!-- 何时启动,大于0的值表示容器启动时初始化此servlet,正值越小优先级越高 -->
        <load-on-startup>1</load-on-startup>
        <!--异步支持-->
<!--        <async-supported>true</async-supported>-->
    </servlet>

    <!-- SpringMVC拦截设置 -->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

十:配置好框架之后,需要创建返回值包装类

1.创建返回值包装类

public class ResultVo<E> {

    @JSONField(ordinal = 1)
    private boolean success;

    @JSONField(ordinal = 2)
    private String msg;

    @JSONField(ordinal = 3)
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private E data;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public E getData() {
        return data;
    }

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

    @Override
    public String
    toString() {
        return "ResultVo{" +
                "success=" + success +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}

2.将创建好的返回值包装类利用,创建错误返回方法和成功返回方法

public class ResultVoUtil {

    public static ResultVo success(String successMsg){
        return ResultVoUtil.success(null,successMsg);
    }

    public static ResultVo success(Object object,String successMsg){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(true);
        resultVo.setMsg(successMsg);
        resultVo.setData(object);
        return resultVo;
    }

    public static ResultVo error(String errorMsg){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(false);
        resultVo.setMsg(errorMsg);
        return resultVo;
    }

    public static ResultVo error(String errorMsg,Object object){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(false);
        resultVo.setMsg(errorMsg);
        resultVo.setData(object);
        return resultVo;
    }
}

十一:创建全局异常处理

1.创建全局异常处理类

//此注解表示会对controller层的异常进行处理
@RestControllerAdvice
public class GloblaException {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //bean级别校验参数时引发的异常
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public ResultVo MissingRequestParamExceptionHandler(BindException e) {
        //e.printStackTrace();
        ArrayList<String> objects = new ArrayList<>();
        List<FieldError> list = e.getFieldErrors();
        for (ObjectError objectError : list) {
            // 输出错误信息
            objects.add(objectError.getDefaultMessage());
        }
        logger.error("请求参数校验异常:" + JSON.toJSONString(objects));
        return ResultVoUtil.error("请求参数校验异常",objects);
    }

    //方法级别校验参数时引发的异常
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public ResultVo ConstraintViolationException(ConstraintViolationException e) {
        //e.printStackTrace();
        ArrayList<String> objects = new ArrayList<>();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> objectError : violations) {
            // 输出错误信息
            objects.add(objectError.getMessageTemplate());
        }
        logger.error("请求参数校验异常:" + JSON.toJSONString(objects));
        return ResultVoUtil.error("请求参数校验异常",objects);
    }

    //@ExceptionHandler(Exception.class)表示自定义异常处理方法,参数是指对Exception会进行处理,@ResponseBody表示是返回前端json格式数据
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResultVo toError(Exception e, HttpServletRequest request) {
        logger.debug(e.getMessage());
        logger.error("业务异常:" + request.getRequestURL().toString() + ":" + e.getMessage());
        return ResultVoUtil.error("业务异常:" + e.getMessage());

    }
}

2.创建自定义异常处理类

public class BussinessExcption extends RuntimeException{

    public BussinessExcption(String message) {
        super(message);
    }

    public BussinessExcption(String message, Throwable cause) {
        super(message, cause);
    }

    @Override
    public String getMessage() {
        return super.getMessage();
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

十二:创建自定义类型转换器

public class StringToDateConverter implements Converter<String, Date> {

    @Override
    public Date convert(String source) {
        if (StringUtils.isBlank(source)) {
            return null;
        }

        long timestamp = Long.parseLong(source);
        return new Date(timestamp * 1000);
    }

}

十三:创建jwtUtil类

public class JwtUtil {

    /**
     * token加密时使用的密钥
     * 一旦得到该密钥也就可以伪造token了
     */
    public static String sercetKey = "InMySchoolOnline";

    /**
     * 代表token的有效时间
     *  30天有效时间
     */
    public final static long keeptime = 30 * 24 * 60 * 60 * 1000;

    /**
     * JWT由3个部分组成,分别是 头部Header,载荷Payload一般是用户信息和声明,签证Signature一般是密钥和签名
     * 当头部用base64进行编码后一般都会呈现eyJ...形式,而载荷为非强制使用,签证则包含了哈希算法加密后的数据,包括转码后的header,payload和sercetKey
     * 而payload又包含几个部分,issuer签发者,subject面向用户,iat签发时间,exp过期时间,aud接收方。
     * @Title: generToken
     * @Description: TODO
     * @param: @param id 用户id
     * @param: @param issuer 签发者
     * @param: @param subject 一般用户名
     * @param: @return
     * @return: String
     * @throws
     */
    public static String generToken(String id, String issuer, String subject) {
        long ttlMillis = keeptime;
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        //使用Hash256算法进行加密
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        //获取系统时间以便设置token有效时间
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(sercetKey);
        //将密钥转码为base64形式,再转为字节码
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        //对其使用Hash256进行加密
        JwtBuilder builder = Jwts.builder().setId(id).setIssuedAt(now);
        //JWT生成类,此时设置iat,以及根据传入的id设置token
        if (subject != null) {
            builder.setSubject(subject);
        }
        if (issuer != null) {
            builder.setIssuer(issuer);
        }
        //由于Payload是非必须加入的,所以这时候要加入检测
        builder.signWith(signatureAlgorithm, signingKey);
        //进行签名,生成Signature
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        //返回最终的token结果
        return builder.compact();
    }
    /**
     * 该函数用于更新token
     * @Title: updateToken
     * @Description: TODO
     * @param: @param token
     * @param: @return
     * @return: String
     * @throws
     */
    public static String updateToken(String token) {
        //Claims就是包含了我们的Payload信息类
        Claims claims = verifyToken(token);
        String id = claims.getId();
        String subject = claims.getSubject();
        String issuer = claims.getIssuer();

        //生成新的token,根据现在的时间
        return generToken(id, issuer, subject);
    }

    /**
     * 将token解密出来,将payload信息包装成Claims类返回
     * @Title: verifyToken
     * @Description: TODO
     * @param: @param token
     * @param: @return
     * @return: Claims
     * @throws
     */
    public static Claims verifyToken(String token) {
        Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(sercetKey))
                .parseClaimsJws(token).getBody();
        return claims;
    }

}

十四:创建token拦截器

1.获取请求头中token

2.使用jwt令牌解析token

3.校验前端传入token是否正确

4.双重验证:登录时将token信息传入redis缓存中,从缓存中获取到信息后在做校验

public class HeaderTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final Logger LOG = Logger.getLogger(HeaderTokenInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                             Object handler) throws Exception {

        // 获取我们请求头中的token验证字符
        String headerToken = httpServletRequest.getHeader("token");
        // 检测当前页面,我们设置当页面不是登录页面时对其进行拦截
        // 具体方法就是检测URL中有没有login字符串
        if (!httpServletRequest.getRequestURI().contains("login")) {
            if (headerToken == null) {
                // 如果token不存在的话,返回错误信息。
                throw new BussinessExcption("token为空");
            }

            try {
                // 对token进行更新与验证
                JwtUtil.updateToken(headerToken);
                LOG.debug("token验证通过");
            } catch (Exception e) {
                LOG.debug("token验证出现异常!");
                // 当token验证出现异常返回错误信息,token不匹配
                throw new BussinessExcption("token不匹配");
            }

            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Claims claims = JwtUtil.verifyToken(headerToken);
            Object user = redisUtil.get(claims.getId());

            if (user == null){
                throw new BussinessExcption("当前未登录");
            }

            Map map = JSON.parseObject((String) user);
            String token = String.valueOf(map.get("token"));
            String tokenTime = String.valueOf(map.get("tokenTime"));
            if (!token.equals(headerToken)){
                throw new BussinessExcption("token不匹配");
            }
            if (sdf.parse(tokenTime).before(date)){
                throw new BussinessExcption("token已过期");
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
                           ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
    }


}

十五:创建跨域拦截器(此类暂未用到)

public class HttpInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 允许跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 允许自定义请求头token(允许head跨域)
        response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }


}

十六:创建redisUtil类

public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    //解决redis存放数据乱码问题
    @PostConstruct
    public void init() {
        initRedisTemplate();
    }

    private void initRedisTemplate() {
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
    }


    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值