搜索词>>cookie 耗时0.0030
  • Control character in cookie value or attribute.

    问题描述java设置cookie报错:java.lang.IllegalArgumentException: Control character in cookie value or attribute. at org.apache.tom问题描述java设置cookie报错:java.lang.IllegalArgumentException: Control character in cookie value or attribute. at org.apache.tomcat.util.http.CookieSupport.isV0Separator(CookieSupport.java:165) at org.apache.tomcat.util.http.Cookies.processCookieHeader(Cookies.java:349) at org.apache.tomcat.util.http.Cookies.processCookies(Cookies.java:176) ..省略...问题原因Java在后端response中设置cookie的时候,cookie的值有中文字符,cookie是不支持中文字符。 解决办法 后台url编码Cookie nickname = new Cookie("_uNickname", URLEncoder.encode(userBase.getNickname(), "utf-8")); 前端 js url解码
  • java WEB中Cookie的操作和使用

    java WEB中Cookie的操作和使用,java,cookie,web<p><strong>java WEB中Cookie的操作和使用</strong><br /> Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器,当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是各自用户自己的数据。</p> <p>java对cookie的操作比较简单,主要介绍下建立cookie和读取cookie,以及如何设定cookie的生命周期和cookie的路径问题。</p> <p>构造Cookie对象</p> <p><strong>Cookie(java.lang.String name, java.lang.String value)</strong></p> <p>设置cookie</p> <p><strong>void setPath(java.lang.String uri) :设置cookie的有效访问路径</strong></p> <p>设置Cookie的有效访问路径,有效访问路径指的事Cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器的时就会带着Cookie信息,否则不带Cookie信息,默认是在当前web项目的路径下</p> <p><strong>void setMaxAge(int expiry) : 设置cookie的有效时间</strong></p> <p>expiry可以是正整数,负整数,和零</p> <p>正整数:表示Cookie数据保存浏览器的缓存到硬盘中,数值表示保存的时间</p> <p>负整数:表示Cookie数据保存到浏览器的内存中,浏览器关闭Cookie就丢失了</p> <p>零:表示删除同名的Cookie数据</p> <p><strong>void setValue(java.lang.String newValue) :设置cookie的值</strong></p> <p>Cookie数据类型只能保存非中文字符串类型的。可以保存多个Cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB</p> <p>发送cookie到浏览器端保存</p> <p><strong>void response.addCookie(Cookie cookie) : 发送cookie</strong></p> <p>服务器端接收cookie</p> <p><strong>Cookie[] request.getCookies() : 接收cookie</strong></p> <p> </p> <p>建立一个生命周期为session回话级别的cookie,即随着浏览器的关闭即消失的cookie</p> <pre> <code class="language-java">HttpServletRequest request HttpServletResponse response Cookie cookie = new Cookie("yourcookiename","yourcookievalue"); response.addCookie(cookie);</code></pre>   <p>建立一个自定义生命周期的cookie,可以设置他的生命周期<br />  </p> <pre> <code class="language-java">cookie = new Cookie("cookiename","cookievalue"); // 设置Cookie的有效时间 cookie.setMaxAge(20);//该cookie只存活20秒,从最后不调该cookie开始计算 // cookie.setMaxAge(-1);//该cookie保存在浏览器内存中,关闭浏览器则销毁该cookie // cookie.setMaxAge(0);//删除根该cookie同名的cookie //设置路径,这个路径即该工程下都可以访问该cookie 如果不设置路径,那么只有设置该cookie路径及其子路径可以访问 cookie.setPath("/"); response.addCookie(cookie);</code></pre> <br /> 下面介绍如何读取cookie,读取cookie代码 <pre> <code class="language-java">Cookie[] cookies = request.getCookies();//这样便可以获取一个cookie数组 for(Cookie cookie : cookies){ cookie.getName();// get the cookie name cookie.getValue(); // get the cookie value }</code></pre> 上面就是基本的读写cookie的操作。我们在实际中最好进行一下封装,比如增加一个cookie,我们关注的是cookie的name,value,生命周期,所以进行封装一个函数,当然还要传入一个response对象 <pre> <code class="language-java">/** * 设置cookie * @param response * @param name cookie名字 * @param value cookie值 * @param maxAge cookie生命周期 以秒为单位 */ public static void addCookie(HttpServletResponse response,String name,String value,int maxAge){ Cookie cookie = new Cookie(name,value); cookie.setPath("/"); if(maxAge>0) cookie.setMaxAge(maxAge); response.addCookie(cookie); }</code></pre> <br /> 读取cookie的时候,为了方便我们的操作,我们希望封装一个函数,只要我们提供cookie的name,我们便可以获取cookie的value,带着这个想法,很容易想到将cookie封装到Map里面,于是进行下面的封装 <pre> <code class="language-java">/** * 根据名字获取cookie * @param request * @param name cookie名字 * @return */ public static Cookie getCookieByName(HttpServletRequest request,String name){ Map<String,Cookie> cookieMap = ReadCookieMap(request); if(cookieMap.containsKey(name)){ Cookie cookie = (Cookie)cookieMap.get(name); return cookie; }else{ return null; } } /** * 将cookie封装到Map里面 * @param request * @return */ private static Map<String,Cookie> ReadCookieMap(HttpServletRequest request){ Map<String,Cookie> cookieMap = new HashMap<String,Cookie>(); Cookie[] cookies = request.getCookies(); if(null!=cookies){ for(Cookie cookie : cookies){ cookieMap.put(cookie.getName(), cookie); } } return cookieMap; }</code></pre> 实验,新建一个简单WEB工程,创建两个jsp文件 <pre> <code class="language-html"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>放COOKIE</title> </head> <body> <% //1.创建Cookie对象 Cookie cookie = new Cookie("tokenID","123456789"); //2.设置Cookie参数 //2.1.设置Cookie的有效路径 cookie.setPath("/");//默认就是web项目的地址 //2.2.设置Cookie的有效时间 cookie.setMaxAge(60*30);//该cookie只存活秒,从最后不调该cookie开始计算 //3.把数据发送到浏览器 response.addCookie(cookie); %> </body> </html></code></pre> 读取的页面代码 <pre> <code class="language-html"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>读COOKIE</title> </head> <body> <% Cookie[] cookies = request.getCookies(); Map<String,Cookie> cookieMap = new HashMap<String,Cookie>(); if(null!=cookies){ for(Cookie cookie : cookies){ cookieMap.put(cookie.getName(), cookie); } } %> <%=cookieMap.get("tokenID").getValue() %> </body> </html></code></pre> 浏览器中F12查看网站信息<br /> <img alt="浏览器中查看cookie" class="img-thumbnail" src="/assist/images/blog/f5036603e7224a62a3de92624b22afeb.jpg" />
  • HttpClient 4 发送自定义的Cookie

    HttpClient 4 发送自定义的Cookie,本教程将重点介绍如何使用Apache HttpClient 4发送自定义Cookie。<h2 style="margin-left:0px; margin-right:0px; text-align:start"><strong>1.概述</strong></h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">本教程将重点介绍<strong>如何使用Apache HttpClient 4发送自定义Cookie</strong>。</span></span></span><br /> <br />  </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><strong>2.在HttpClient上配置Cookie管理</strong></h2> <h3 style="margin-left:0px; margin-right:0px; text-align:start"><strong>2.1。4.3之后的HttpClient</strong></h3> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">在较新的HttpClient 4.3中,我们将利用负责构建和配置客户端的流利构建器API。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">首先,我们需要创建一个Cookie存储并在商店中设置我们的示例Cookie:</span></span></span></p> <pre> <code class="language-java">BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie);</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start">然后,我们可以在HttpClient上设置这个cookie存储并发送请求:<br />  </p> <pre> <code class="language-java">@Test public void whenSettingCookiesOnTheHttpClient_thenCookieSentCorrectly() throws ClientProtocolException, IOException { BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie); HttpClient client = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build(); final HttpGet request = new HttpGet("http://www.github.com"); response = client.execute(request); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">一个非常重要的元素是<em><strong>域</strong></em>被设置上的Cookie - <strong>没有设置正确的域,客户端将不会发送该cookie,</strong>在所有!</span></span></span></p> <h3 style="margin-left:0px; margin-right:0px; text-align:start"><strong>2.2。4.3之前的HttpClient</strong></h3> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">使用旧版本的HttpClient(4.3之前) - cookie存储直接在<em>HttpClient</em>上设置:</span></span></span></p> <pre> <code class="language-java">@Test public void givenUsingDeprecatedApi_whenSettingCookiesOnTheHttpClient_thenCorrect() throws ClientProtocolException, IOException { BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie); DefaultHttpClient client = new DefaultHttpClient(); client.setCookieStore(cookieStore); HttpGet request = new HttpGet("http://www.github.com"); response = client.execute(request); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">除了客户端的构建方式之外,与前面的示例没有其他区别。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><strong>3.在请求中设置Cookie</strong></h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">如果在整个HttpClient上设置cookie不是一个选项,我们可以单独配置cookie的请求:</span></span></span></p> <pre> <code class="language-java">@Test public void whenSettingCookiesOnTheRequest_thenCookieSentCorrectly() throws ClientProtocolException, IOException { BasicCookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234"); cookie.setDomain(".github.com"); cookie.setPath("/"); cookieStore.addCookie(cookie); instance = HttpClientBuilder.create().build(); HttpGet request = new HttpGet("http://www.github.com"); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); // localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); // before 4.3 response = instance.execute(request, localContext); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); }</code></pre> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><strong>4.在低层请求中设置Cookie</strong></h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">在HTTP请求中设置Cookie的低级替代方案将会将其设置为原始标题:</span></span></span></p> <pre> <code class="language-java">@Test public void whenSettingCookiesOnARequest_thenCorrect() throws ClientProtocolException, IOException { instance = HttpClientBuilder.create().build(); HttpGet request = new HttpGet("http://www.github.com"); request.setHeader("Cookie", "JSESSIONID=1234"); response = instance.execute(request); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff"><strong>与使用内置cookie支持相比,</strong>这当然更<strong>容易出错</strong> - 例如,注意我们在这种情况下不再设置域 - 这是不正确的。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><strong>5.总结</strong></h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">本文说明了如何<strong>使用HttpClient发送自定义的,用户控制的Cookie</strong>。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:#535353"><span style="font-family:raleway"><span style="background-color:#ffffff">请注意,这与让HttpClient处理由服务器设置的cookie不同 - 但是它却是在低级别手动控制客户端。</span></span></span></p>
  • Jquery cookie插件实现点击获取验证码后60秒内禁止重新获取

    Jquery cookie插件实现点击获取验证码后60秒内禁止重新获取,可直接拿走用,jquery,验证码获取Jquery cookie插件实现点击获取验证码后60秒内禁止重新获取,可直接拿走用<br /> 注意:本例子依赖一下库<br /> 1.jQuery<br /> 2.jQuery cookie<br /> 可根据自身环境进行修改<br /> <br /> 代码: <pre> <code class="language-html"><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>验证码获取按钮防止刷新</title> <link rel="stylesheet" type="text/css" href="../libs/bootstrap/bootstrap-3.3.7/css/bootstrap.css"> <style type="text/css"> .content{ margin: 20px 0px 0px 20px; } </style> </head> <body> <div class="form-inline content"> <h1>验证码获取按钮防止刷新</h1> <div class="alert alert-info base64-de-out"> 注意:<br> 1.本案例依赖jQuery;<br> 2.本案例依赖jQuery的cookie插件<br> </div> <input type="text" class="form-control" placeholder="请输入邮箱地址"><button class="btn btn-default test-btn">获取验证码</button> </div> <script type="text/javascript" src="../libs/jQuery/jquery.js"></script> <script type="text/javascript" src="../libs/jQuery/plugins/cookie/jquery.cookie.js"></script> <script type="text/javascript" src="../libs/bootstrap/bootstrap-3.3.7/js/bootstrap.js"></script> <script type="text/javascript"> $(function(){ var btn=$('.test-btn'); //1.默认检测验证码按钮 checkResendCode(btn); //2.绑定点击事件 $(btn).click(function(){ //do somthing //code .... //设置按钮状态 resendCode(this); }); }) /**检查cookie中的验证码统计是否存在***/ function checkResendCode(btnObject) { if($.cookie('captchaCount')){ var count=$.cookie('captchaCount'); //设置按钮的显示和不可用状态 $(btnObject).html(count+'秒重新获取').attr('disabled',true); var resend=setInterval(function(){ if (count > 0){ $(btnObject).html(count+'秒重新获取').attr('disabled',true).css('cursor','not-allowed'); $.cookie("captchaCount", count, {path: '/', expires: (1/86400)*count}); }else { clearInterval(resend); btn.html("获取验证码").attr('disabled',false); } count--; },1000); } } /**重新发送事件***/ function resendCode(btnObject) { var count=60; var resend = setInterval(function(){ if (count > 0){ $(btnObject).html(count+"秒重新获取"); $.cookie("captchaCount", count, {path: '/', expires: (1/86400)*count}); }else { clearInterval(resend); $(btnObject).html("&nbsp;获取验证码&nbsp;").attr('disabled',false); } count--; }, 1000); $(btnObject).attr('disabled',true); } </script> </body> </html></code></pre> <br /> 效果如下:<br /> <img alt="验证码重新获取按钮" class="img-thumbnail" src="/assist/images/blog/e8dbb0e355fd4a0cac29993fff3cf1ea.png" /><br />  
  • centos 6 nginx+php7环境配置

    centos 6 nginx+php7环境配置centos 6 nginx+php7环境配置$title(php.conf) # # The default server # server { listen 80 default_server; server_name localhost 127.0.0.1; location / { root /var/www/html; index index.php index.html ; #以下三行,目的是将代理服务器收到的用户的信息传到真实服务器上 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #cookie proxy_set_header Cookie $http_cookie; } location ~ .*\.php(\/.*)*$ { root /var/www/html; #以下三行,目的是将代理服务器收到的用户的信息传到真实服务器上 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #cookie proxy_set_header Cookie $http_cookie; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; set $path_info ""; set $real_script_name $fastcgi_script_name; if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") { set $real_script_name $1; set $path_info $2; } fastcgi_param SCRIPT_FILENAME $document_root$real_script_name; fastcgi_param SCRIPT_NAME $real_script_name; fastcgi_param PATH_INFO $path_info; include fastcgi_params; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } ​​​​​​​代码段 小部件
  • spring boot 入门之spring session&RESTful APIs

    spring boot 入门之spring session实现restful apis。通过spring boot或者spring mvc整合spring session的方式来实现session的共享达到应用可以水平扩展集群。<h2>一.简介</h2>    spring boot 入门之spring session实现restful apis。通过前面的了解和使用,我们知道可以通过spring boot或者spring mvc整合spring session的方式来实现session的共享达到应用可以水平扩展集群。session默认情况是存了一个cookie在响应的数据里面,然后每次通过cookie来验证session的,但是restful设计中一般不会使用cookie,所以spring session提供了将session id存放在http协议的header中,本文主要讲解如何使用。 <h2>二.编码介绍</h2> <h3>HttpSession & RESTful APIs</h3> 原理:Spring Session 可以允许session在header里面提供来实现RESTful APIs <h3>Spring配置</h3> 在创建一个spring boot项目后,加入相关的依赖。现在我们就可以来进行相关配置。这个配置主要负责创建一个servlet Filter替换原有的HttpSession 使用spring session.主要添加以下spring 相关配置: <pre> <code class="language-java">@Configuration @EnableRedisHttpSession //① public class HttpSessionConfig { @Bean public LettuceConnectionFactory connectionFactory() { return new LettuceConnectionFactory(); //②注意,spring boot项目这里不需要创建一个链接工厂,在application配置文件中配置了相关信息会默认生成一个链接工厂供使用。 } @Bean public HttpSessionStrategy httpSessionStrategy() { return new HeaderHttpSessionStrategy(); //③ } }</code></pre>   ①<code>@EnableRedisHttpSession</code> 注解用来创建一个spring的过滤器类,类的名称为 <code>springSessionRepositoryFilter</code> 这个过滤器用来替换原生的 <code>HttpSession</code> 使用spring session。这个例子中,Spring Session通过Redis来实现存储。<br />   ②创建了一个<code>RedisConnectionFactory</code> 来使Spring Session链接到Redis Server。关于spring data redis相关配置可以参考之前的spring redis整合。(注意,spring boot项目这里不需要创建一个链接工厂,在application配置文件中配置了相关信息会默认生成一个链接工厂供使用。)<br />   ③我们自定义了Spring  Session的HttpSession ,将它整合到了HTTP协议的header里面,替换掉默认的放在cookie中。 <h3>HttpSessionListener 即session监听处理</h3> Spring Session支持<code>HttpSessionListener</code>,通过将<code>SessionDestroyedEvent</code> 和SessionCreatedEvent转换成 <code>HttpSessionEvent</code> 被定义在SessionEventHttpSessionListenerAdapter来实现。需要使用监听,注意以下几点: <ul> <li>确保你所实现的<code>SessionRepository</code> 支持并且配置到启动<code>SessionDestroyedEvent</code> 和SessionCreatedEvent</li> <li>将<code>SessionEventHttpSessionListenerAdapter</code> 配置为spring容器中的一个bean</li> <li>注入每一个<code>HttpSessionListener</code> 到SessionEventHttpSessionListenerAdapter</li> </ul> 如果你使用Redis的方式记录HttpSession,你需要将每一个HttpSessionListener配置为bean。例如,假设你想要支持Spring Security的并发控制,并且需要使用HttpSessionEventPublisher,你可以简单地将HttpSessionEventPublisher添加为一个bean。 在Java配置中,这可能如下所示: <pre> <code class="language-java">@Configuration @EnableRedisHttpSession public class RedisHttpSessionConfig { @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } // ... }</code></pre> 或者xml <pre> <code class="language-xml"><bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/></code></pre>
  • java常见面试题

    java常见面试题之冒泡排序<h2>引言</h2> 记录常见的java面试题及解决思路方法。 <h2>java冒泡排序</h2> <pre> <code class="language-java">package net.xqlee.project; public class TestMaoPao { public static void main(String[] args) { int[] arr = new int[] { 0, 2, 3, 7, -1, 90, 290, -1, 100 }; int swap = 0; for (int i = 0; i < arr.length; i++) { for (int j = i; j < arr.length; j++) { if (arr[j] > arr[i]) { swap = arr[i]; arr[i] = arr[j]; arr[j] = swap; } } } System.out.println(arr[0]); } } </code></pre> <br /> 冒泡排序原理: 从第一个开始,与后面的每一个比较,找到比他大/小的就交换,一轮下来就可以将最大/小值放在索引的第一个位置,后面以此类推。 <h2><strong>servlet执行流程</strong></h2>   客户端发出http请求,web服务器将请求转发到servlet容器,servlet容器解析url并根据web.xml找到相对应的servlet,并将request、response对象传递给找到的servlet,servlet根据request就可以知道是谁发出的请求,请求信息及其他信息,当servlet处理完业务逻辑后会将信息放入到response并响应到客户端。 <h2><strong>springMVC的执行流程</strong></h2>   springMVC是由dispatchservlet为核心的分层控制框架。首先客户端发出一个请求web服务器解析请求url并去匹配dispatchservlet的映射url,如果匹配上就将这个请求放入到dispatchservlet,dispatchservlet根据mapping映射配置去寻找相对应的handel,然后把处理权交给找到的handel,handel封装了处理业务逻辑的代码,当handel处理完后会返回一个逻辑视图modelandview给dispatchservlet,此时的modelandview是一个逻辑视图不是一个正式视图,所以dispatchservlet会通过viewresource视图资源去解析modelandview,然后将解析后的参数放到view中返回到客户端并展现。 <h2><strong>Java设计模式思想(单列模式,工厂模式,策略模式,共23种设计模式)</strong></h2> <ul> <li>a) 单例模式:单例模式核心只需要new一个实例对象的模式,比如数据库连接,在线人数等,一些网站上看到的在线人数统计就是通过单例模式实现的,把一个计时器存放在数据库或者内存中,当有人登陆的时候取出来加一再放回去,有人退出登陆的时候取出来减一再放回去,但是当有两个人同时登陆的时候,会同时取出计数器,同时加一,同时放回去,这样的话数据就会错误,所以需要一个全局变量的对象给全部人使用,只需要new出一个实例对象,这就是单例模式的应用,并且单例模式节省资源,因为它控制了实例对象的个数,并有利于gc回收。</li> <li>b) 策略模式:就是将几个类中公共的方法提取到一个新的类中,从而使扩展更容易,保证代码的可移植性,可维护性强。比如有个需求是写鸭子对象,鸭子有叫,飞,外形这三种方法,如果每个鸭子类都写这三个方法会出现代码的冗余,这时候我们可以把鸭子中的叫,飞,外形这三个方法提取出来,放到鸭父类中,让每个鸭子都继承这个鸭父类,重写这三个方法,这样封装的代码可移植性强,当用户提出新的需求比如鸭子会游泳,那么对于我们oo程序员来讲就非常简单了我们只需要在鸭父类中加一个游泳的方法,让会游泳的鸭子重写游泳方法就可以了。</li> <li>c) 工厂模式:简单的工厂模式主要是统一提供实例对象的引用,通过工厂模式接口获取实例对象的引用。比如一个登陆功能,后端有三个类,controller类,interface类,实现接口的实现类。当客户端发出一个请求,当请求传到controller类中时,controller获取接口的引用对象,而实现接口的实现类中封装好了登陆的业务逻辑代码。当你需要加一个注册需求的时候只需要在接口类中加一个注册方法,实现类中实现方法,controller获取接口的引用对象即可,不需要改动原来的代码,这种做法是的可拓展性强。</li> </ul> <h2><strong>内部类与外部类的调用</strong></h2> <ul> <li>a) 内部类可以直接调用外部类包括private的成员变量,使用外部类引用的this.关键字调用即可</li> <li>b) 而外部类调用内部类需要建立内部类对象</li> </ul> <h2><strong>AOP与IOC的概念(即spring的核心)</strong></h2> <ul> <li>a) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度。而spring的核心是IOC控制反转和AOP面向切面编程。IOC控制反转主要强调的是程序之间的关系是由容器控制的,容器控制对象,控制了对外部资源的获取。而反转即为,在传统的编程中都是由我们创建对象获取依赖对象,而在IOC中是容器帮我们创建对象并注入依赖对象,正是容器帮我们查找和注入对象,对象是被获取,所以叫反转。</li> <li>b) AOP:面向切面编程,主要是管理系统层的业务,比如日志,权限,事物等。AOP是将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为切面(aspect),切面将那些与业务逻辑无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。</li> </ul> <h2><strong>Arraylist与linkedlist的区别</strong></h2> a) 都是实现list接口的列表,arraylist是基于数组的数据结构,linkedlist是基于链表的数据结构,当获取特定元素时,ArrayList效率比较快,它通过数组下标即可获取,而linkedlist则需要移动指针。当存储元素与删除元素时linkedlist效率较快,只需要将指针移动指定位置增加或者删除即可,而arraylist需要移动数据。 <h2><strong>数据库优化</strong></h2> <ul> <li>a) 选择合适的字段,比如邮箱字段可以设为char(6),尽量把字段设置为notnull,这样查询的时候数据库就不需要比较null值</li> <li>b) 使用关联查询( left join on)查询代替子查询</li> <li>c) 使用union联合查询手动创建临时表</li> <li>d) 开启事物,当数据库执行多条语句出现错误时,事物会回滚,可以维护数据库的完整性</li> <li>e) 使用外键,事物可以维护数据的完整性但是它却不能保证数据的关联性,使用外键可以保证数据的关联性</li> <li>f) 使用索引,索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快的多的速度检索特定的行,特别是对于max,min,order by查询时,效果更明显</li> <li>g) 优化的查询语句,绝大多数情况下,使用索引可以提高查询的速度,但如果sql语句使用不恰当的话,索引无法发挥它的特性。</li> </ul> <h2>Java集合类框架的基本接口有哪些</h2> Collection集合接口,<br /> List、set实现Collection接口,<br /> arraylist、linkedlist,vector实现list接口,<br /> stack继承vector,Map接口,<br /> hashtable、hashmap实现map接口 <h2><strong>事物的理解</strong></h2> <ul> <li>a) 事物具有原子性,一致性,持久性,隔离性</li> <li>b) 原子性:是指在一个事物中,要么全部执行成功,要么全部失败回滚。</li> <li>c) 一致性:事物执行之前和执行之后都处于一致性状态</li> <li>d) 持久性:事物多数据的操作是永久性</li> <li>e) 隔离性:当一个事物正在对数据进行操作时,另一个事物不可以对数据进行操作,也就是多个并发事物之间相互隔离。</li> </ul> <h2><strong>对象的创建</strong></h2> <ul> <li>a) 遇到一个新类时,会进行类的加载,定位到class文件</li> <li>b) 对所有静态成员变量初始化,静态代码块也会执行,而且只在类加载的时候执行一次</li> <li>c) New 对象时,jvm会在堆中分配一个足够大的存储空间</li> <li>d) 存储空间清空,为所有的变量赋默认值,所有的对象引用赋值为null</li> <li>e) 根据书写的位置给字段一些初始化操作</li> <li>f) 调用构造器方法(没有继承)</li> </ul> <h2>JAVA WEB 九大内置对象</h2>   九大内置对象分别是: request response session application out page config exception pageContent<br /> <br />   其中: <ul> <li>request  response  out page config exception pageContent对象的有效范围是当前页面的应用 </li> <li>session 有效范围是当前会话(当前客户端的所有页面)</li> <li>application 有效范围是整个应用程序,只要服务器不关闭对象就有效</li> </ul> ====================================================================<br /> request<br /> ====================================================================<br /> request.getParameter();获得用户提交的表单信息<br /> request.setCharacterEncoding("UTF-8");设置请求编码,防止乱码<br /> request.setAttribute("Unmae", new Object());将数据保存到request范围内的变量中<br /> request.forward(String Url);转发<br /> request.getRequestURL();获得当前页的IE地址<br /> request.getHeader("resref");获得请求也的IE地址<br /> request.getRemoteAddr();获得用户的IP地址<br /> ====================================================================<br /> cookie<br /> ====================================================================<br /> cookie.getCookies()获得所有cookie对象的集合<br /> cookie.getName()获得指定名称的cookie<br /> cookie.getValue()获得cookie对象的值<br /> URLEncoder.encode();将需要保存到cookie中的数据进行编码<br /> URLEncoder.decode();读取cookie信息时将信息解码<br /> ====================================================================<br /> response<br /> ====================================================================<br /> response.addCookie()将一个cookie对象发送到客户端<br /> response.sendRedirect(String path); 重定向<br /> ====================================================================<br /> application<br /> ====================================================================<br /> application.setAttribute(key,value);给application添加属性值<br /> application.getAttribute(key,value);获取指定的值<br /> ====================================================================<br /> session<br /> ====================================================================<br /> session.setMaxInactiveInterval(int num);设置session对象的有效活动时间<br /> session.isNew();判断是否为新用户  返回Boolean<br /> session.setAttribute();<br /> session.getAttribute();<br /> session.invalidate();销毁当前session<br /> ====================================================================
  • ajax和axios、fetch 区别

    1.jQuery ajax$.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {},1.jQuery ajax$.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function () {} });传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。JQuery ajax 是对原生XHR的封装,除此以外还增添了对JSONP的支持。经过多年的更新维护,真的已经是非常的方便了,优点无需多言;如果是硬要举出几个缺点,那可能只有:1.本身是针对MVC的编程,不符合现在前端MVVM的浪潮2.基于原生的XHR开发,XHR本身的架构不清晰。3.JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)4.不符合关注分离(Separation of Concerns)的原则5.配置和调用方式非常混乱,而且基于事件的异步模型不友好。PS:MVVM(Model-View-ViewModel), 源自于经典的 Model–View–Controller(MVC)模式。MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的最重要一环。如下图所示:​2.axiosaxios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax,想必让axios进入了很多人的目光中。axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:1.从浏览器中创建 XMLHttpRequest2.支持 Promise API3.客户端支持防止CSRF4.提供了一些并发请求的接口(重要,方便了很多的操作)5.从 node.js 创建 http 请求6.拦截请求和响应7.转换请求和响应数据8.取消请求9.自动转换JSON数据PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。3.fetchtry { let response = await fetch(url); let data = response.json(); console.log(data); } catch(e) { console.log("Oops, error", e); }fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。fetch的优点:1.符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里2.更好更方便的写法坦白说,上面的理由对我来说完全没有什么说服力,因为不管是Jquery还是Axios都已经帮我们把xhr封装的足够好,使用起来也足够方便,为什么我们还要花费大力气去学习fetch?我认为fetch的优势主要优势就是:1.语法简洁,更加语义化 2.基于标准 Promise 实现,支持 async/await 3.同构方便,使用 [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) 4.更加底层,提供的API丰富(request, response) 5.脱离了XHR,是ES规范里新的实现方式最近在使用fetch的时候,也遇到了不少的问题:fetch是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装。例如:1)fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。 2)fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: 'include'}) 3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费 4)fetch没有办法原生监测请求的进度,而XHR可以总结axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。
  • Java编程之Apache Shiro Web支持

    组态,将Shiro集成到任何Web应用程序中的最简单的方法是在web.xml中配置Servlet ContextListener和Filter,了解如何读取Shiro的INI配置。<h1>组态</h1> <p>将Shiro集成到任何Web应用程序中的最简单的方法是在web.xml中配置Servlet ContextListener和Filter,了解如何读取Shiro的INI配置。大部分INI配置格式本身在配置页面的INI Sections部分中定义,但我们将在此处介绍一些其他特定于Web的部分。</p>  <strong>使用Spring?</strong> <hr /> <p>Spring Framework用户不会执行此设置。如果你使用Spring,你将需要阅读关于Spring特定的web配置。</p>   <h3>web.xml</h3> <h4>Shiro 1.2以后</h4> <p>在Shiro 1.2及更高版本中,标准Web应用程序通过添加以下XML块来初始化Shiro <code>web.xml</code>:</p> <pre> <code class="language-xml"><listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> ... <filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> </code></pre> <p>这假设一个Shiro INI 配置文件位于以下两个位置之一,使用以前找到的位置:</p> <ol> <li><code>/WEB-INF/shiro.ini</code></li> <li><code>shiro.ini</code> 文件在类路径的根。</li> </ol> <p>这里是上面的配置:</p> <ul> <li> <p>的<code>EnvironmentLoaderListener</code>初始化四郎<code>WebEnvironment</code>实例(包含一切四郎需要操作,包括<code>SecurityManager</code>),并使其在访问<code>ServletContext</code>。如果您需要随时获取此<code>WebEnvironment</code>实例,则可以调用<code>WebUtils.getRequiredWebEnvironment(servletContext)</code>。</p> </li> <li> <p>该<code>ShiroFilter</code>会利用这个<code>WebEnvironment</code>来执行所有必要的安全操作的任何过滤的要求。</p> </li> <li> <p>最后,该<code>filter-mapping</code>定义确保所有请求都被过滤<code>ShiroFilter</code>,建议大多数Web应用程序使用,以确保任何请求都是安全的。</p> </li> </ul>  <strong>ShiroFilter过滤器映射</strong> <hr /> <p>通常希望在任何其他“filter-mapping”声明之前定义“ShiroFilter filter-mapping”,以确保Shiro也能在这些过滤器中运行。</p>   <h5>自定义<code>WebEnvironment</code>类</h5> <p>默认情况下,<code>EnvironmentLoaderListener</code>将创建一个<code>IniWebEnvironment</code>实例,它承担Shiro的基于INI的配置。如果愿意,您可以<code>WebEnvironment</code>通过在<code>ServletContext</code> <code>context-param</code>中指定一个自定义实例来指定<code>web.xml</code>:</p> <pre> <code class="language-xml"><context-param> <param-name>shiroEnvironmentClass</param-name> <param-value>com.foo.bar.shiro.MyWebEnvironment</param-value> </context-param> </code></pre> <p>这允许您自定义如何解析配置格式并将其表示为<code>WebEnvironment</code>实例。您可以对现有<code>IniWebEnvironment</code>的自定义行为进行子类化,或者完全支持不同的配置格式。例如,如果有人想要在XML而不是INI中配置Shiro,他们可以创建一个基于XML的实现,例如<code>com.foo.bar.shiro.XmlWebEnvironment</code>。</p> <h5>自定义配置位置</h5> <p>本<code>IniWebEnvironment</code>类希望读取并加载INI配置文件。默认情况下,此类将自动查找以下两个位置的Shiro <code>.ini</code>配置(按顺序):</p> <ol> <li><code>/WEB-INF/shiro.ini</code></li> <li><code>classpath:shiro.ini</code></li> </ol> <p>它将使用先找到的。</p> <p>然而,如果你希望将你的配置在其他位置,则可能与另一指定位置<code>context-param</code>在<code>web.xml</code>:</p> <pre> <code class="language-xml"><context-param> <param-name>shiroConfigLocations</param-name> <param-value>YOUR_RESOURCE_LOCATION_HERE</param-value> </context-param> </code></pre> <p>默认情况下,<code>param-value</code>期望由<code>ServletContext.getResource</code>方法定义的规则可解析。例如,<code>/WEB-INF/some/path/shiro.ini</code></p> <p>但是,您也可以使用Shiro的ResourceUtils类支持的适当资源前缀来指定特定的文件系统,类路径或URL位置,例如:</p> <ul> <li><code>file:/home/foobar/myapp/shiro.ini</code></li> <li><code>classpath:com/foo/bar/shiro.ini</code></li> <li><code>url:http://confighost.mycompany.com/myapp/shiro.ini</code></li> </ul> <h4>Shiro 1.1和更早版本</h4> <p>在1.1或更早版本的Web应用程序中启用Shiro的最简单的方法是定义IniShiroFilter并指定<code>filter-mapping</code>:</p> <pre> <code class="language-xml"><filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> </filter> ... <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --> <!-- requests. Usually this filter mapping is defined first (before all others) to --> <!-- ensure that Shiro works in subsequent filters in the filter chain: --> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> </code></pre> <p>此定义要求您的INI配置位于类路径(例如<code>classpath:shiro.ini</code>)的根目录下的shiro.ini文件中。</p> <h5>自定义路径</h5> <p>如果不想将INI配置放入<code>/WEB-INF/shiro.ini</code>或<code>classpath:shiro.ini</code>,您可以根据需要指定自定义资源位置。添加<code>configPath init-param</code>并指定资源位置:</p> <pre> <code class="language-xml"><filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> <init-param> <param-name>configPath</param-name> <param-value>/WEB-INF/anotherFile.ini</param-value> </init-param> </filter> ... </code></pre> <p>未限定(无限额或“非前缀”)<code>configPath</code>值被假定为<code>ServletContext</code>资源路径,可通过该<br /> <code>ServletContext.getResource</code>方法定义的规则解析。</p>  <strong>ServletContext资源路径 - Shiro 1.2+</strong> <hr /> <p>ServletContext资源路径在Shiro 1.2和更高版本中可用。在1.1和更早的版本中,所有<code>configPath</code>的定义必须指定<code>classpath:</code>,<code>file:</code>或<code>url:</code>前缀。</p> <p>你也可以指定其他非<code>ServletContext</code>使用资源位置<code>classpath:</code>,<code>url:</code>或<code>file:</code>前缀分别表示classpath中,URL或文件系统位置。例如:</p> <pre> <code class="language-xml">... <init-param> <param-name>configPath</param-name> <param-value>url:http://configHost/myApp/shiro.ini</param-value> </init-param> ... </code></pre> <h5>内联配置</h5> <p>最后,还可以将INI配置嵌入到web.xml中,而不使用INI文件。您可以使用<code>config init-param</code>而不是<code>configPath</code>:</p> <pre> <code class="language-xml"><filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> <init-param><param-name>config</param-name><param-value> # INI Config Here </param-value></init-param> </filter> ... </code></pre> <p>直列配置往往细小型或简单的应用,但它通常是更方便的外部化它的原因如下专用shiro.ini文件:</p> <ul> <li>您可以编辑安全配置很多,并且不想将修订控制'noise'添加到web.xml文件</li> <li>您可能希望将安全配置与web.xml配置的其余部分分离</li> <li>您的安全配置可能会变大,您希望保持web.xml精简并更易于阅读</li> <li>你有一个复杂的构建系统,其中相同的shiro配置可能需要在多个地方引用</li> </ul> <p>这取决于你 - 使用什么对你的项目有意义。</p> <h3>Web INI配置</h3> <p>除了标准<code>[main]</code>,<code>[users]</code>并<code>[roles]</code>在主已经说明部分配置章节中,你还可以指定一个特定的网络<code>[urls]</code>在部分<code>shiro.ini</code>文件:</p> <pre> <code># [main], [users] and [roles] above here ... [urls] ... </code></pre> <p>该<code>[urls]</code>部分允许你做一些事情,不以任何Web框架存在,我们见过的:确定特设的过滤器链在应用程序中任何匹配的URL路径的能力!</p> <p>这是<em>远远</em>比你通常定义过滤链更灵活,功能强大,简洁的<code>web.xml</code>:即使你从未使用过任何其他的功能,该功能提供四郎也只有这个使用,仅此一项就使值得使用。</p> <h4>[urls]</h4> <p>该<code>urls</code>节中每行的格式如下:</p> <pre> <code>_URL_Ant_Path_Expression_ = _Path_Specific_Filter_Chain_ </code></pre> <p>例如:</p> <pre> <code>... [urls] /index.html = anon /user/create = anon /user/** = authc /admin/** = authc, roles[administrator] /rest/** = authc, rest /remoting/rpc/** = authc, perms["remote:invoke"] </code></pre> <p>接下来,我们将详细介绍这些行的含义。</p> <p>等号(=)左侧的令牌是相对于Web应用程序的上下文根的Ant样式路径表达式。</p> <p>例如,假设您有以下<code>[urls]</code>行:</p> <pre> <code>/account/** = ssl, authc </code></pre> <p>该行指出:“以我的应用程序的路径的任何请求<code>/account</code>或任何它的子路径(<code>/account/foo</code>,<code>/account/bar/baz</code>,等),将触发”SSL,authc'过滤器链“。我们将在下面介绍过滤链。</p> <p>请注意,所有路径表达式都与应用程序的上下文根相关。这意味着如果你部署你的应用程序一天,<code>www.somehost.com/myapp</code>然后,然后将其部署到<code>www.anotherhost.com</code>(没有'myapp'子路径),模式匹配仍然会工作。所有路径都是相对于HttpServletRequest.getContextPath()值。</p>  <strong>订单事项!</strong> <hr /> <p>URL路径表达式根据传入请求按照它们定义的顺序和<em>第一个匹配的WINS</em>进行评估。例如,让我们假设有以下链定义:</p> <pre> <code>/account/** = ssl, authc /account/signup = anon </code></pre> <p>如果传入的请求打算到达<code>/account/signup/index.html</code>(所有“anon'ymous用户可访问),<em>它将永远不会被处理!</em>。原因是该<code>/account/**</code>模式首先匹配传入请求,并将所有剩余定义“短路”。</p> <p>始终记住根据<em>FIRST MATCH WINS</em>策略定义您的过滤器链!</p> <p> </p>   <h5>过滤器链定义</h5> <p>等号(=)右侧的令牌是以逗号分隔的过滤器列表,以对匹配该路径的请求执行。它必须匹配以下格式:</p> <pre> <code>filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN] </code></pre> <p>哪里:</p> <ul> <li><em>filterN</em>是在<code>[main]</code>部分中定义的过滤器bean的名称</li> <li><code>[optional_configN]</code>是一个可选的括号字符串,对于<em>该特定路径</em>(每个过滤器,<em>特定</em>于<em>路径的</em>配置!)<em>的特定</em>过滤器具有含义。如果过滤器不需要为该URL路径指定特定的配置,您可以丢弃括号,<code>filterN[]</code>只是变成了<code>filterN</code>。</li> </ul> <p>并且因为过滤器令牌定义链(aka List),记住顺序很重要!按您希望请求流过链的顺序定义逗号分隔的列表。</p> <p>最后,如果不满足其必要条件(例如,执行重定向,使用HTTP错误代码进行响应,直接呈现等),则每个过滤器都可以自由地处理响应。否则,预期允许请求通过链继续到最终目的地视图。</p>  <strong>小费</strong> <hr /> <p>能够对路径特定配置(即<code>[optional_configN]</code>过滤器令牌的一部分)做出反应是对于Shiro过滤器可用的独特特征。</p> <p>如果你想创建自己的<code>javax.servlet.Filter</code>实现,也可以这样做,请确保你的过滤器子类org.apache.shiro.web.filter.PathMatchingFilter</p> <p> </p>   <h6>可用过滤器</h6> <p>可用于过滤器链定义的“池”过滤器在此<code>[main]</code>部分中定义。在主节中分配给它们的名称是在过滤器链定义中使用的名称。例如:</p> <pre> <code>[main] ... myFilter = com.company.web.some.FilterImplementation myFilter.property1 = value1 ... [urls] ... /some/path/** = myFilter </code></pre> <h2>默认过滤器</h2> <p>当运行Web应用程序时,Shiro将创建一些有用的默认<code>Filter</code>实例,并使其在<code>[main]</code>部分自动可用。您可以像配置<code>main</code>其他bean一样配置它们,并在链定义中引用它们。例如:</p> <pre> <code>[main] ... # Notice how we didn't define the class for the FormAuthenticationFilter ('authc') - it is instantiated and available already: authc.loginUrl = /login.jsp ... [urls] ... # make sure the end-user is authenticated. If not, redirect to the 'authc.loginUrl' above, # and after successful authentication, redirect them back to the original account page they # were trying to view: /account/** = authc ... </code></pre> <p>自动可用的默认Filter实例由DefaultFilter枚举定义,枚举的<code>name</code>字段是可用于配置的名称。他们是:</p> <table> <thead> <tr> <th>过滤器名称</th> <th>类</th> </tr> </thead> <tbody> <tr> <td>anon</td> <td>org.apache.shiro.web.filter.authc.AnonymousFilter</td> </tr> <tr> <td>authc</td> <td>org.apache.shiro.web.filter.authc.FormAuthenticationFilter</td> </tr> <tr> <td>authcBasic</td> <td>org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter</td> </tr> <tr> <td>登出</td> <td>org.apache.shiro.web.filter.authc.LogoutFilter</td> </tr> <tr> <td>noSessionCreation</td> <td>org.apache.shiro.web.filter.session.NoSessionCreationFilter</td> </tr> <tr> <td>烫发</td> <td>org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter</td> </tr> <tr> <td>港口</td> <td>org.apache.shiro.web.filter.authz.PortFilter</td> </tr> <tr> <td>休息</td> <td>org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter</td> </tr> <tr> <td>角色</td> <td>org.apache.shiro.web.filter.authz.RolesAuthorizationFilter</td> </tr> <tr> <td>ssl</td> <td>org.apache.shiro.web.filter.authz.SslFilter</td> </tr> <tr> <td>用户</td> <td>org.apache.shiro.web.filter.authc.UserFilter</td> </tr> </tbody> </table> <h2>启用和禁用过滤器</h2> <p>与任何过滤器链定义机制(<code>web.xml</code>,Shiro的INI等)的情况一样,只需通过将过滤器包含在过滤器链定义中来启用它,并通过从链定义中删除它来禁用它。</p> <p>但是在Shiro 1.2中添加的一个新功能是能够启用或禁用过滤器,而不从过滤器链中删除它们。如果启用(默认设置),则会按预期对请求进行过滤。如果禁用,则过滤器将允许请求立即传递到中的下一个元素<code>FilterChain</code>。您可以通常基于配置属性触发过滤器的启用状态,或者甚至可以<em>根据请求</em>触发它。</p> <p>这是一个强大的概念,因为与更改静态过滤器链定义(这将是永久和不灵活的)相比,基于某些要求启用或禁用过滤器通常更方便。</p> <p>Shiro通过其OncePerRequestFilter抽象父类完成此操作。所有Shiro的开箱即用的Filter实现子类化这一个,因此可以启用或禁用,而不从过滤器链中删除它们。你可以为你自己的过滤器实现子类这个类,如果你也需要这个功能*。</p> <p>* SHIRO-224希望能为任何过滤器启用此功能,而不只是那些子类<code>OncePerRequestFilter</code>。如果这对您很重要,请投票支持此问题。</p> <h3>一般启用/禁用</h3> <p>该OncePerRequestFilter(及其所有子类)支持启用/所有的请求,以及在每个请求的基础禁用。</p> <p>对所有请求的一般启用或禁用过滤器是通过将其<code>enabled</code>属性设置为true或false来实现的。默认设置是<code>true</code>因为大多数过滤器本身需要执行,如果它们在链中配置。</p> <p>例如,在shiro.ini中:</p> <pre> <code>[main] ... # configure Shiro's default 'ssl' filter to be disabled while testing: ssl.enabled = false [urls] ... /some/path = ssl, authc /another/path = ssl, roles[admin] ... </code></pre> <p>此示例显示可能许多URL路径都可能要求请求必须由SSL连接保护。在开发过程中设置SSL可能会令人沮丧和耗时。在开发过程中,可以禁用ssl过滤器。部署到生产时,您可以使用一个配置属性启用它 - 这比手动更改所有URL路径或维护两个Shiro配置要容易得多。</p> <h3>请求特定的启用/禁用</h3> <p><code>OncePerRequestFilter</code>实际上根据其<code>isEnabled(request, response)</code>方法确定是否启用或禁用过滤器。</p> <p>此方法默认返回属性的值,<code>enabled</code>用于一般启用/禁用所有请求,如上所述。如果要根据<em>请求特定</em>条件启用或禁用过滤器,则可以覆盖该<code>OncePerRequestFilter</code><code>isEnabled(request,response)</code>方法以执行更具体的检查。</p> <h3>路径特定的启用/禁用</h3> <p>Shiro的PathMatchingFilter(一个子类)<code>OncePerRequestFilter</code>能够基于被过滤的<em>特定路径</em>对配置做出反应,这意味着除了传入的请求和响应之外,您还可以基于路径和特定于路径的配置启用或禁用过滤器。</p> <p>如果您需要能够对匹配路径和路径特定配置做出反应,以确定是启用还是禁用过滤器,而不是<code>OncePerRequestFilter</code> <code>isEnabled(request,response)</code>覆盖方法,那么您将覆盖该<code>PathMatchingFilter</code> <code>isEnabled(request,response,path,pathConfig)</code>方法。</p> <h2>会话管理</h2> <h3>Servlet容器会话</h3> <p>在Web环境中,Shiro的默认会话管理器<code>SessionManager</code>实现是<code>ServletContainerSessionManager</code>。这个非常简单的实现将所有会话管理职责(包括如果servlet容器支持它的会话群集)委托给运行时Servlet容器。它本质上是一个桥梁,用于Shiro的会话API到servlet容器,没有别的。</p> <p>使用此默认值的一个好处是,使用现有servlet容器会话配置(超时,任何容器特定的集群机制等)的应用程序将按预期工作。</p> <p>这个默认的缺点是,你绑定到servlet容器的特定会话行为。例如,如果您想集群会话,但在生产中使用Jetty进行测试和Tomcat,则容器特定的配置(或代码)将不可移植。</p> <h4>Servlet容器会话超时</h4> <p>如果使用默认的servlet容器支持,您可以在Web应用程序的<code>web.xml</code>文件中按预期配置会话超时。例如:</p> <pre> <code class="language-xml"><session-config> <!-- web.xml expects the session timeout in minutes: --> <session-timeout>30</session-timeout> </session-config> </code></pre> <h3>本地会话</h3> <p>如果希望您的会话配置设置和集群在servlet容器(例如Jetty在测试中,但是Tomcat或JBoss在生产中)是可移植的,或者您想要控制特定的会话/集群功能,您可以启用Shiro的本地会话管理。</p> <p>“Native”这个词意味着Shiro自己的企业会话管理实现将用于支持所有<code>Subject</code>和<code>HttpServletRequest</code>会话,并完全绕过servlet容器。但是放心 - Shiro直接实现了Servlet规范的相关部分,所以任何现有的web / http相关代码如预期一样工作,并且不需要“知道”Shiro是透明地管理会话。</p> <h4>DefaultWebSessionManager</h4> <p>要为Web应用程序启用本机会话管理,您需要配置一个本地的Web会话管理器来覆盖默认的基于servlet容器的会话管理器。你可以通过配置<code>DefaultWebSessionManager</code>Shiro的实例来实现<code>SecurityManager</code>。例如,在<code>shiro.ini</code>:</p> <p><strong>shiro.ini本地Web会话管理</strong></p> <pre> <code>[main] ... sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager # configure properties (like session timeout) here if desired # Use the configured native session manager: securityManager.sessionManager = $sessionManager </code></pre> <p>一旦声明,您可以配置<code>DefaultWebSessionManager</code>实例与本地会话选项,如会话超时和聚类配置,如会话管理部分所述。</p> <h5>本地会话超时</h5> <p>配置<code>DefaultWebSessionManager</code>实例后,按会话管理:会话超时中所述配置会话超时</p> <h5>会话Cookie</h5> <p>在<code>DefaultWebSessionManager</code>支持两个特定网络的配置属性:</p> <ul> <li><code>sessionIdCookieEnabled</code> (布尔)</li> <li><code>sessionIdCookie</code>,一个Cookie实例。</li> </ul>  <strong>Cookie作为模板</strong> <hr /> <p>该<code>sessionIdCookie</code>属性本质上是一个模板 - 您配置<code>Cookie</code>实例属性,并且此模板将用于在运行时使用适当的会话ID值设置实际的HTTP Cookie。</p>   <h6>会话Cookie配置</h6> <p>DefaultWebSessionManager的<code>sessionIdCookie</code>默认实例是a <code>SimpleCookie</code>。这个简单的实现允许对要在http Cookie上配置的所有相关属性进行JavaBeans风格的属性配置。</p> <p>例如,您可以设置Cookie域:</p> <pre> <code>[main] ... securityManager.sessionManager.sessionIdCookie.domain = foo.com </code></pre> <p>有关其他属性,请参阅SimpleCookie JavaDoc。</p> <p>cookie的默认名称<code>JSESSIONID</code>与servlet规范一致。此外,Shiro的cookie支持<code>HttpOnly</code>标志。该<code>sessionIdCookie</code>套<code>HttpOnly</code>到<code>true</code>默认情况下,额外的安全性。</p>  <strong>注意</strong> <hr /> <p>Shiro的<code>Cookie</code>概念<code>HttpOnly</code>甚至在Servlet 2.4和2.5环境中支持该标志(而Servlet API只在2.6或更高版本中支持它)。</p>   <h6>禁用会话Cookie</h6> <p>如果您不想使用会话Cookie,可以通过将<code>sessionIdCookieEnabled</code>属性配置为false 来禁用它们。例如:</p> <p><strong>禁用本机会话Cookie</strong></p> <pre> <code>[main] ... securityManager.sessionManager.sessionIdCookieEnabled = false </code></pre> <h2>记住我的服务</h2> <p>Shiro将执行'rememberMe'服务,如果<code>AuthenticationToken</code>实现的<code>org.apache.shiro.authc.RememberMeAuthenticationToken</code>接口。此接口指定一个方法:</p> <pre> <code>boolean isRememberMe(); </code></pre> <p>如果此方法返回<code>true</code>,则Shiro将记住会话中的最终用户身份。</p>  <strong>UsernamePasswordToken和RememberMe</strong> <hr /> <p>常用的<code>UsernamePasswordToken</code>已经实现了<code>RememberMeAuthenticationToken</code>接口并支持rememberMe登录。</p>   <h3>计划支持</h3> <p>要以程序方式使用rememberMe,可以将值设置为<code>true</code>支持此配置的类。例如,使用标准<code>UsernamePasswordToken</code>:</p> <pre> <code>UsernamePasswordToken token = new UsernamePasswordToken(username, password); token.setRememberMe(true); SecurityUtils.getSubject().login(token); ... </code></pre> <h3>基于表单的登录</h3> <p>对于Web应用程序,<code>authc</code>过滤器默认为a <code>FormAuthenticationFilter</code>。这支持将“rememberMe”布尔作为form / request参数读取。默认情况下,它期望请求参数被命名<code>rememberMe</code>。这里是一个示例shiro.ini配置支持这:</p> <pre> <code>[main] authc.loginUrl = /login.jsp [urls] # your login form page here: login.jsp = authc </code></pre> <p>在您的网络表单中,有一个名为“rememberMe”的复选框:</p> <pre> <code><form ...> Username: <input type="text" name="username"/> <br/> Password: <input type="password" name="password"/> ... <input type="checkbox" name="rememberMe" value="true"/>Remember Me? ... </form> </code></pre> <p>默认情况下,<code>FormAuthenticationFilter</code>会寻找名为请求参数<code>username</code>,<code>password</code>和<code>rememberMe</code>。如果这些不同于您在表单中使用的表单字段名称,则需要在上配置名称<code>FormAuthenticationFilter</code>。例如,在<code>shiro.ini</code>:</p> <pre> <code>[main] ... authc.loginUrl = /whatever.jsp authc.usernameParam = somethingOtherThanUsername authc.passwordParam = somethingOtherThanPassword authc.rememberMeParam = somethingOtherThanRememberMe ... </code></pre> <h3>Cookie配置</h3> <p>您可以<code>rememberMe</code>通过设置默认的{{RememberMeManager}}的各种cookie属性来配置cookie的功能。例如,在shiro.ini中:</p> <pre> <code>[main] ... securityManager.rememberMeManager.cookie.name = foo securityManager.rememberMeManager.cookie.maxAge = blah ... </code></pre> <p>请参阅<code>CookieRememberMeManager</code>和支持<code>SimpleCookie</code>JavaDoc的配置属性。</p> <h3>自定义 <code>RememberMeManager</code></h3> <p>应该注意的是,如果默认的基于cookie的实现<code>RememberMeManager</code>不能满足你的需要,你可以插入任何你喜欢的<code>securityManager</code>类似,你将配置任何其他对象引用:</p> <pre> <code>[main] ... rememberMeManager = com.my.impl.RememberMeManager securityManager.rememberMeManager = $rememberMeManager </code></pre> <h2>JSP / GSP标签库</h2> <p>Apache Shiro提供了一个<code>Subject</code>-aware JSP / GSP标签库,允许您根据当前主题的状态控制您的JSP,JSTL或GSP页面输出。这对于基于查看网页的当前用户的身份和授权状态来个性化视图是非常有用的。</p> <h3>标签库配置</h3> <p>标签库描述符(TLD)文件捆绑在<code>shiro-web.jar</code>中<code>META-INF/shiro.tld</code>文件。要使用任何标记,请将以下行添加到JSP页面的顶部(或在您定义页面指令的任何位置):</p> <pre> <code><%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> </code></pre> <p>我们使用<code>shiro</code>前缀来指示shiro标签库命名空间,但是您可以分配任何您喜欢的名称。</p> <p>现在,我们将介绍每个标记,并说明如何使用它来呈现网页。</p> <h3>该<code>guest</code>标签</h3> <p><code>guest</code>只有当前<code>Subject</code>被视为“访客”时,标记才会显示其包装内容。客人是<code>Subject</code>没有身份的任何人。也就是说,我们不知道用户是谁,因为他们没有登录,他们不记得(从记住我服务)从以前的网站访问。</p> <p>例:</p> <pre> <code class="language-xml"><shiro:guest> Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today! </shiro:guest> </code></pre> <p>该<code>guest</code>标签是的逻辑相反的<code>user</code>标记。</p> <h3>该<code>user</code>标签</h3> <p><code>user</code>仅当当前<code>Subject</code>被视为“用户”时,标记才会显示其包装内容。在此上下文中的“用户”被定义为<code>Subject</code>具有已知标识,或者来自成功认证或者来自“记住我”服务。请注意,此标记在语义上与已认证的标记不同,后者比此标记更受限制。</p> <p>例:</p> <pre> <code class="language-xml"><shiro:user> Welcome back John! Not John? Click <a href="login.jsp">here<a> to login. </shiro:user> </code></pre> <p>该<code>user</code>标签是的逻辑相反的<code>guest</code>标记。</p> <h3>该<code>authenticated</code>标签</h3> <p>仅当当前用户<em>在其当前会话期间</em>已成功通过身份验证<em>时,</em>才显示主体内容。它比“用户”标签限制性更强。它在逻辑上与“notAuthenticated”标签相反。</p> <p>该<code>authenticated</code>标签将显示其包裹内容仅在当前<code>Subject</code>已成功验证<em>了当前会话中</em>。这是一个比用户更严格的标签,用于保证敏感工作流中的身份。</p> <p>例:</p> <pre> <code class="language-xml"><shiro:authenticated> <a href="updateAccount.jsp">Update your contact information</a>. </shiro:authenticated> </code></pre> <p>该<code>authenticated</code>标签是的逻辑相反的<code>notAuthenticated</code>标记。</p> <h3>该<code>notAuthenticated</code>标签</h3> <p>该<code>notAuthenticated</code>如果当前标签将显示其包裹内容<code>Subject</code>已<strong>不</strong>还成功地在本届会议期间进行身份验证。</p> <p>例:</p> <pre> <code class="language-xml"><shiro:notAuthenticated> Please <a href="login.jsp">login</a> in order to update your credit card information. </shiro:notAuthenticated> </code></pre> <p>该<code>notAuthenticated</code>标签是的逻辑相反的<code>authenticated</code>标记。</p> <h3>该<code>principal</code>标签</h3> <p>该<code>principal</code>标签将输出主题的<code>principal</code>(标识属性)或本金的属性。</p> <p>没有任何标记属性,标记将呈现<code>toString()</code>主体的值。例如(假设主体是字符串用户名):</p> <pre> <code class="language-xml">Hello, <shiro:principal/>, how are you today? </code></pre> <p>这是(大多数)等价于以下:</p> <pre> <code>Hello, <%= SecurityUtils.getSubject().getPrincipal().toString() %>, how are you today? </code></pre> <h4>类型主体</h4> <p>该<code>principal</code>标签假设默认情况下,该校长印的是<code>subject.getPrincipal()</code>价值。但是如果要打印一个<em>不是</em>主要主体的值,而是在主体的{ principal集合中另一个值,那么您可以通过类型获取该主体,并打印该值。</p> <p>例如,打印主题的用户ID(而不是用户名),假设ID在主体集合中:</p> <pre> <code>User ID: <principal type="java.lang.Integer"/> </code></pre> <p>这是(大多数)等价于以下:</p> <pre> <code>User ID: <%= SecurityUtils.getSubject().getPrincipals().oneByType(Integer.class).toString() %> </code></pre> <h4>主要财产</h4> <p>但是如果主体(上面的默认主要主体或者“类型化”主体)是一个复杂对象而不是一个简单的字符串,并且你想引用该主体上的一个属性呢?您可以使用该<code>property</code>属性指示要读取的属性的名称(必须通过JavaBeans兼容的getter方法访问)。例如(假设主要主体是User对象):</p> <pre> <code>Hello, <shiro:principal property="firstName"/>, how are you today? </code></pre> <p>这是(大多数)等价于以下:</p> <pre> <code>Hello, <%= SecurityUtils.getSubject().getPrincipal().getFirstName().toString() %>, how are you today? </code></pre> <p>或者,结合type属性:</p> <pre> <code>Hello, <shiro:principal type="com.foo.User" property="firstName"/>, how are you today? </code></pre> <p>这在很大程度上等同于以下:</p> <pre> <code>Hello, <%= SecurityUtils.getSubject().getPrincipals().oneByType(com.foo.User.class).getFirstName().toString() %>, how are you today? </code></pre> <h3>该<code>hasRole</code>标签</h3> <p><code>hasRole</code>仅当当前<code>Subject</code>分配了指定的角色时,标记才会显示其包装内容。</p> <p>例如:</p> <pre> <code><shiro:hasRole name="administrator"> <a href="admin.jsp">Administer the system</a> </shiro:hasRole> </code></pre> <p>该<code>hasRole</code>标签是的逻辑相反lacksRole标记。</p> <h3>该<code>lacksRole</code>标签</h3> <p><code>lacksRole</code>仅当当前<code>Subject</code> <strong>未</strong>分配指定角色时,标记才会显示其包装内容。</p> <p>例如:</p> <pre> <code class="language-xml"><shiro:lacksRole name="administrator"> Sorry, you are not allowed to administer the system. </shiro:lacksRole> </code></pre> <p>该<code>lacksRole</code>标签是的逻辑相反hasRole标记。</p> <h3>该<code>hasAnyRole</code>标签</h3> <p>该<code>hasAnyRole</code>如果当前标签将显示其包裹内容<code>Subject</code>被分配<em>任何</em>指定的角色从一个逗号分隔的角色名称列表。</p> <p>例如:</p> <pre> <code class="language-xml"><shiro:hasAnyRoles name="developer, project manager, administrator"> You are either a developer, project manager, or administrator. </shiro:lacksRole> </code></pre> <p>该<code>hasAnyRole</code>标签目前还没有一个逻辑相反的标记。</p> <h3>该<code>hasPermission</code>标签</h3> <p><code>hasPermission</code>只有当前的<code>Subject</code>“has”(暗示)指定的权限,标签才会显示其包装的内容。也就是说,用户具有指定的能力。</p> <p>例如:</p> <pre> <code class="language-xml"><shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission> </code></pre> <p>该<code>hasPermission</code>标签是的逻辑相反lacksPermission标记。</p> <h3>该<code>lacksPermission</code>标签</h3> <p><code>lacksPermission</code>只有当前的<code>Subject</code> <strong>DOES没有</strong>(暗示)指定的权限,标签才会显示其包装的内容。也就是说,用户<strong>没有</strong>指定的能力。</p> <p>例如:</p> <pre> <code class="language-xml"><shiro:lacksPermission name="user:delete"> Sorry, you are not allowed to delete user accounts. </shiro:hasPermission> </code></pre> <p>该<code>lacksPermission</code>标签是的逻辑相反hasPermission标记。</p> <h2>借给文档</h2> <p>虽然我们希望本文档帮助您与Apache Shiro正在进行的工作,社区正在不断改进和扩展文档。如果您希望帮助Shiro项目,请考虑更正,扩展或添加您需要的文档。你提供的每一点帮助扩大了社区,反过来又改善了Shiro。</p> <p>提交文档的最简单方法是通过点击以下<code>Edit</code>链接提交拉取请求,将其发送到用户论坛或用户邮件列表。</p>
  • spring boot 入门之整合spring session实现session共享

    spring boot 入门之整合spring session实现session共享。一直以来Java编程中web项目中的session共享问题都是一个很难解决的问题。接下来将讲解通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。<h2>一.前言</h2>   spring boot 入门之整合spring session实现session共享。一直以来Javaweb项目中的session共享问题都是一个很难解决的问题。原因是session是由启动servlet的当前web容器所创建和管理。与其他地方的web容器很难通讯。导致无法共享也就很难实现集群化。这里将通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。 <h2>二.编码</h2> <strong>pom.xml文件:</strong> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project</groupId> <artifactId>demo-springboot-spring-session</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>demo-springboot-spring-session</name> <description>lee-leftso-v2.0</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> 核心配置类,HttpSessionConfig: <pre> <code class="language-java">package net.xqlee.project.config; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; /** 启用redis session **/ /*** * * @author xqlee maxInactiveIntervalInSeconds设置session超时时间,默认1800秒 */ @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class HttpSessionConfig { // spring boot项目可以直接配置application配置文件自动注册redis connect 工厂 // 非boot项目则需要再这里配置一下redis得链接工厂 } </code></pre> <strong>编写一个测试的controller,TestController:</strong> <pre> <code class="language-java">package net.xqlee.project.controller; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("/test.do") public Object testSession(HttpServletRequest request) { Map<String, Object> obj = new HashMap<>(); obj.put("result", true); request.getSession().setAttribute("time", new Date().getTime()); obj.put("time", request.getSession().getAttribute("time")); return obj; } } </code></pre> <p><strong>application配置文件配置redis的链接信息</strong></p> <pre> <code class="language-html">spring.redis.host=10.1.1.2 spring.redis.password= spring.redis.port=6379 </code></pre> <p><span style="color:#0066cc"><strong>具体的redis配置信息根据自己的环境改变</strong></span></p> <h2>三.测试</h2> 启动spring boot项目,注意观察启动日志<br /> <img alt="启动日志" class="img-thumbnail" src="/assist/images/blog/5c72b8f1caff4859b11a60a590bbbf2c.png" /><br /> 从上方日志可以看到springSessionRepositoryFilter已经启用<br /> <br /> 在浏览器中访问测试controller的地址test.do<br /> 通过谷歌浏览器的调试模式可以看到SESSION的cookie<br /> <img alt="cookie" class="img-thumbnail" src="/assist/images/blog/a39e346b5dca4a1493812e9c15793ed4.png" /><br /> 再通过redis的可视化链接工具链接过去查看:<br /> <img alt="session redis" class="img-thumbnail" src="/assist/images/blog/6f5d096243ea4d4d85d53bd83105efa6.png" /><br /> 上图可以看到: <ul> <li>session id和浏览器中的对应;</li> <li>自己添加的time属性;</li> </ul> 到这里spring  boot 整合spring session 通过redis的方式持久化完成。<br /> <br />