ssm项目集成nginx反向代理、负载均衡和redis数据缓存

1.nginx使用以及出现相关问题

1.1.nginx下载后,找到配置文件,并修改:

#gzip  on;
    server {
        listen       8800;//反向代理端口,地址栏访问时使用
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass  http://localhost:8888;//反向代理转发的目的端口(ssm项目端口)
            #root   html;
            #index  index.html index.htm;
        }

疑问:为什么proxy_pass http://localhost:8888;//反向代理转发的目的端口(ssm项目端口)不写成proxy_pass http://localhost:8888/项目名称;(因为真实访问的是: http://localhost:8888/项目名称)?
配置如下:

#gzip  on;
    #include vhost/*.conf;
    server {
        listen       8800;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
proxy_pass  http://localhost:8888/xlh_ssm_web;
            #root   html;
            #index  index.html index.htm;
        }

原因:写成proxy_pass http://localhost:8888/项目名称;会发生重定向次数过多访问不了网页问题,chrom给出的解决方法是清除cookic缓存,但不管用,会发生访问超时问题。
那么为什么会发生重定向次数过多访问不了网页问题?
这也就是nginx重定向的缺点:
由上面例子发现,如果写成proxy_pass http://localhost:8888/项目名称;,也就表明了localhost:8800localhost:8888/项目名称等效,此时再地址栏上用localhost:8800/项目名称就等于 http://localhost:8888/项目名称/项目名称了,这就是重定向次数过多访问不了网页。但也许你会这么想如果只用http://localhost:8888访问呢?答案也是一样的。
因此上面配置就是解决方法,访问方式就是localhost:反向代理端口/项目名称

因为出现重定向次数过多访问不了网页是因为 http://localhost:8800/的时候,地址栏访问了 http://localhost:8800/http://localhost:8800/到nginx服务器变成了 http://localhost:8800//为什么会变成这样?原因是proxy_pass中ip+port后的项目名称不加/),根据proxy_pass端口后有字符串的规律,将location在地址栏之后的字符串截取加到proxy_pass后,实际就访问了http://localhost:8888/项目名称/,由于security配置了过滤规则,这又得重定向到${pageContext.request.contextPath}/login.do,地址栏就去掉原先的location加上了${pageContext.request.contextPath}/login.do,变成了 http://localhost:8800/xlh_ssm_web/login.do,请求到了nginx后加上一个/变成http://localhost:8800//xlh_ssm_web/login.do,然后又根据proxy_pass端口后有字符串的规律,截取/xlh_ssm_web/login.do加到proxy_pass后访问,地址栏就剩http://localhost:8800/,如此循环反复,这就是为什么一直是显示http://localhost:8800//请求每次都加一个/,而实际请求路径不同的原因,真实路劲迭代

http://localhost:8888/项目名称//xlh_ssm_web/login.do/xlh_ssm_web/login.do/xlh_ssm_web/login.do.......

1.2.一直是login.jsp页面原因:

配置:

#gzip  on;
    #include vhost/*.conf;
    server {
        listen       8800;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
proxy_pass  http://localhost:8888/xlh_ssm_web/;
            #root   html;
            #index  index.html index.htm;
        }

其实我觉得这是nginx反向代理的特性造成的:
由于等效于http://localhost:8888/项目名称/,这时由于<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>就会重定向到login.jsp,根据nginx302重定向特性,原链接http://localhost:8800/去掉loaction加上/login.jsp,就变成了http://localhost:8800/login.jsphttp://localhost:8888/项目名称/login.jsp),与原来不用nginx代理等效,

 <!-- 定义跳转的具体的页面 ,需要添加一个成功后的跳转页面(每个人不同)-->
        <security:form-login
                login-page="/login.jsp"
                login-processing-url="/login.do"
                default-target-url="/index.jsp"
                authentication-failure-url="/failer.jsp"
                authentication-success-forward-url="/pages/main.jsp"
        />

但填入密码登陆时,login.jsp代码中<form action="${pageContext.request.contextPath}/login.do" method="post">,根据nginx302重定向特性,原链接不变http://localhost:8800${pageContext.request.contextPath}/login.do,即http://localhost:8800/项目名称/login.do,与http://localhost:8888/项目名称/login.do不等效(我们期望的是http://localhost:8800/项目名称/login.do,这才能访问),由于规则<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->/ <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>过滤/**,即包括http://localhost:8800/项目名称/login.do/项目名称/login.do,其实你可以看成请求一个需要ROLE_USER的角色才能登陆的页面,可此刻我们正要登陆拿权限,还没拿到就要跳到其他页面,显然又被security拦截跳到http://localhost:8800/login.jsp,如此循环反复,就出现了重定向次数过多访问不了页面。

1.3.总结:

  • 一次请求:客户端请求-》nginx处理-》服务器
  • nginx配置文件proxy_pass中ip+port后的项目名称不加/,每次请求到达nginx都要加在port后加/
  • 第一次访问用到location,重定向后用跳转的页面取代location,例如/项目名称/login.jsp取代地址栏中port后的/,之后重定向就是页面取代页面了,也就是http://localhost:8800不变,不再有location。
  • 地址栏显示的是每次请求到nginx没有处理路径的路径(不包括nginx加上的/)

2.ssm项目使用nginx负载均衡的配置(这只是实验,为了验证而已)


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实验:两个页面忽有忽无,多访问几次,结果如预期所想。
地址栏访问:localhost:8800
在这里插入图片描述
地址栏访问:localhost:8800/项目名称
在这里插入图片描述
学习视频

几个注意事项:

  • 代码taskkill /f /t /im nginx.exe能够杀死nginx所有子进程,每次修改配置文件都要taskkill /f /t /im nginx.exe一次,防止因为缓存上次修改结果使得修改结果不生效。
  • D:\Nginx\nginx-1.18.0>nginx -t nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in D:\Nginx\nginx-1.18.0/conf/nginx.conf:44 nginx: configuration file D:\Nginx\nginx-1.18.0/conf/nginx.conf test failed可能因为配置文件中由中文字符如分号、斜杆等情况。

3.ssm项目集成redis

在这里插入图片描述
redis.properties:

redis.host=127.0.0.1
redis.port=6379
redis.maxIdle=300
redis.maxWaitMillis=1000
redis.maxTotal=600
redis.testOnBorrow=true
redis.testOnReturn=true

redis-context.xml(3.1.用此配置文件,3.2.和3.3.用3.2.的)

<?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="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
        <property name="testOnReturn" value="${redis.testOnReturn}" />
    </bean>
    <!--设置链接属性-->
    <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"/>
    <!-- Jedis模板配置  -->
    <bean id = "jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory"   ref="connectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer"></property>
        <property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
    </bean>

</beans>

spring-mvc.xml
新增

 <!-- 引入redis配置文件 -->
    <import resource="classpath:redis-context.xml"/>

3.1.用法1(默认JDK序列化存储本地Redis):

ssm项目pom.xml文件:

 <!--redis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <!-- config redis data and client jar-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
        <!--commons-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

使用:

Controller
@RequestMapping("/product")
public class ProductController {
 @Autowired
    private RedisTemplate  redisTemplate; //注入
@RequestMapping("/findAll.do")
    @RolesAllowed("ADMIN")
    protected ModelAndView findAll(){
        ModelAndView mv = new ModelAndView();
        List<Product> ps = productService.findAll();
        List<Product> absentValue = null;

//        //redis代码
        boolean absentBoolean = redisTemplate.hasKey("productFindAll");
        System.out.println("通过setIfAbsent(K key, V value)方法判断变量值absentValue是否存在:" + absentBoolean);
        if(!absentBoolean){
            mv.addObject("productList",ps);
            redisTemplate.opsForList().rightPush("productList",ps);
        }else {         
            absentValue = (List<Product>)redisTemplate.opsForList().leftPop("productFindAll");           
            System.out.println("key的value:" + absentValue);
            mv.addObject("productList",absentValue);
        }
        mv.setViewName("product-list1");
        return mv;
    }
    }

redis命令行乱码,解决之后补上,如有小友明知,敬请告知,万分感谢。

3.2.用法2(GenericJackson2JsonRedisSerializer序列化存储非本地Redis):

ssm项目pom.xml文件:
增加了com.fasterxml.jackson.core依赖,为了能够存储其他对象而不仅仅是String,同时,尽量使用高版本,否则会爆出无法创建xxxx,没有xxxbean,应该至少有一个等等页面出错的错误

 <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.3</version>
        </dependency>

具体文件:

<!--redis-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.3</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <!-- config redis data and client jar-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.8.6.RELEASE</version>
        </dependency>
        <!--commons-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

redis-context.xml:

<?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="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
        <property name="testOnReturn" value="${redis.testOnReturn}" />
    </bean>
    <!--设置链接属性-->
    <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"/>
    <!-- Jedis模板配置  -->
    <bean id = "GenericJackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"></bean>
    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory"   ref="connectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer"></property>
        <property name="valueSerializer" ref="GenericJackson2JsonRedisSerializer"></property>
    </bean>

</beans>

使用:

@Controller
@RequestMapping("/user")
public class UserController {
 @RequestMapping("/findById")
    public ModelAndView findById(@RequestParam(name = "id",required = true) String userId){
        ModelAndView mv = new ModelAndView();
        BoundValueOperations<String,UserInfo> boundValueOperations =
                redisTemplate.boundValueOps(userId);
        UserInfo userInfo = boundValueOperations.get();
        if(userInfo!=null){
            System.out.println("从redis获取key"+userInfo.toString());
            mv.addObject("user",userInfo);
        }else{
            userInfo = userService.findById(userId);
            System.out.println("从数据库获取key"+userInfo.toString());
            boundValueOperations.set(userInfo);
            mv.addObject("user",userInfo);
        }

        mv.addObject("user",userInfo);
        mv.setViewName("user-show");
        return mv;
    }
    }

3.3.用法3(GenericJackson2JsonRedisSerializer序列化存储本地Redis):

相比于用法1,解决了乱码问题;相比于用法2,数据存在本地redis服务器
使用:

@Controller
@RequestMapping("/user")
public class UserController {
 @RequestMapping("/findAll.do")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public ModelAndView findAll(){
        ModelAndView mv = new ModelAndView();
        List<UserInfo> userInfoList = null;
        ValueOperations<String,List<UserInfo>> valueOperations = redisTemplate1.opsForValue();
        boolean absentBoolean = redisTemplate.hasKey("userFindAll");
        if(!absentBoolean){
            userInfoList = userService.findAll();
            System.out.println("通过setIfAbsent(K key, V value)方法判断变量值absentValue是否存在:" + absentBoolean);
            mv.addObject("userList",userInfoList);
            valueOperations.set("userFindAll",userInfoList);
        }else {
            userInfoList = valueOperations.get("userFindAll");
            System.out.println("从redis获取:" + absentBoolean);
            mv.addObject("userList",userInfoList);
        }
        mv.setViewName("user-list1");
        return mv;
    }
}

使用jdk默认序列化和GenericJackson2JsonRedisSerializer存储非字符串对象差异:
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fire king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值