整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          HTML meta標簽的介紹

          1. <meta name="keywords" content="關鍵字">

          content里面寫網(wǎng)頁的關鍵字,可以寫多個,用逗號隔開。

          2. <meta name="description" content="網(wǎng)站的介紹">

          content里面寫關于網(wǎng)站的介紹描述

          3. <meta name="robots" content="all">

          這個是用來定義搜索爬蟲的方式,這里的content的屬性有:all,none,index,noindex,follow,nofollow,默認是‘a(chǎn)ll’,

          all:文件將被檢索,且頁面上的鏈接可以被查詢;none:跟all相反;index:文件將被檢索;noindex:文件將不被檢索,但是頁面上的鏈接可以被找到;follow:網(wǎng)頁上的鏈接可以被找到;nofollow:網(wǎng)頁可以搜索到,但是網(wǎng)頁上的鏈接不可以被找到

          4. <meta name="author" content="作者">

          content里面可以寫網(wǎng)站作者的相關資料如名字,郵箱,QQ什么的

          5. <meta name="copyright" content="版權信息">

          這里寫版權信息相關的東西

          6. <meta charset="UTF-8" />

          網(wǎng)頁的編碼格式:

          UTF-8:世界通用的編碼格式

          GB2312:簡體中文

          其他的網(wǎng)上可以找到

          7. <meta http-equiv="Refresh" content="3;url=http://www.mackxin.com">

          網(wǎng)頁在3秒后自動跳轉到www.mackxin.com這個網(wǎng)站上,如果不寫右邊的網(wǎng)址,表示3秒后刷新當前網(wǎng)頁

          如果你也有好的想法,可以關注我的微信公眾號:馨客棧 ,也可以加入我的新的QQ群:65202496來一起交流學習好玩有趣的想法。進群可以也拉到微信群一起交流各種有趣好玩的分享

          端功能問題系列文章,點擊上方合集↑

          序言

          大家好,我是大澈!

          本文2100+,整篇閱讀大約需要3分鐘。

          本文主要內(nèi)容分三部分,如果您只需要解決問題,請閱讀第一、二部分即可。如果您有更多時間,進一步學習問題相關知識點,請閱讀至第三部分。

          感謝關注微信公眾號:“程序員大澈”,然后加入問答群,從此讓解決問題的你不再孤單!

          點登錄系統(tǒng)實現(xiàn)基于SpringBoot

          今天的干貨有點濕,里面夾雜著我的淚水。可能也只有代碼才能讓我暫時的平靜。通過本章內(nèi)容你將學到單點登錄系統(tǒng)和傳統(tǒng)登錄系統(tǒng)的區(qū)別,單點登錄系統(tǒng)設計思路,Spring4 Java配置方式整合HttpClient,整合Redis ,HttpClient簡易教程。還在等什么?擼起袖子開始干吧!

          效果圖:8081端口是sso系統(tǒng),其他兩個8082和8083端口模擬兩個系統(tǒng)。登錄成功后檢查Redis數(shù)據(jù)庫中是否有值

          技術:SpringBoot,SpringMVC,Spring,SpringData,Redis,HttpClient

          說明:本章的用戶登錄注冊的代碼部分已經(jīng)在SpringBoot基礎入門中介紹過了,這里不會重復貼代碼。

          源碼: https://github.com/ITDragonBlog/daydayup/tree/master/SpringBoot-SSO

          SpringBoot基礎入門:http://www.cnblogs.com/itdragon/p/8047132.html

          單點登錄系統(tǒng)簡介

          在傳統(tǒng)的系統(tǒng),或者是只有一個服務器的系統(tǒng)中。Session在一個服務器中,各個模塊都可以直接獲取,只需登錄一次就進入各個模塊。若在服務器集群或者是分布式系統(tǒng)架構中,每個服務器之間的Session并不是共享的,這會出現(xiàn)每個模塊都要登錄的情況。這時候需要通過單點登錄系統(tǒng)(Single Sign On)將用戶信息存在Redis數(shù)據(jù)庫中實現(xiàn)Session共享的效果。從而實現(xiàn)一次登錄就可以訪問所有相互信任的應用系統(tǒng)。

          單點登錄系統(tǒng)實現(xiàn)

          Maven項目核心配置文件 pom.xml 需要在原來的基礎上添加 httpclient和jedis jar包

           <dependency> <!-- http client version is 4.5.3 -->
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
          </dependency>
          <dependency> <!-- redis java client version is 2.9.0 -->
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
          </dependency>

          Spring4 Java配置方式

          這里,我們需要整合httpclient用于各服務之間的通訊(也可以用okhttp)。同時還需要整合redis用于存儲用戶信息(Session共享)。

          在Spring3.x之前,一般在應用的基本配置用xml,比如數(shù)據(jù)源、資源文件等。業(yè)務開發(fā)用注解,比如Component,Service,Controller等。其實在Spring3.x的時候就已經(jīng)提供了Java配置方式。現(xiàn)在的Spring4.x和SpringBoot都開始推薦使用Java配置方式配置bean。它可以使bean的結構更加的清晰。

          整合 HttpClient

          HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。HttpClient4.5系列教程 : http://blog.csdn.net/column/details/httpclient.html

          首先在src/main/resources 目錄下創(chuàng)建 httpclient.properties 配置文件

          #設置整個連接池默認最大連接數(shù)
          http.defaultMaxPerRoute=100
          #設置整個連接池最大連接數(shù)
          http.maxTotal=300
          #設置請求超時
          http.connectTimeout=1000
          #設置從連接池中獲取到連接的最長時間
          http.connectionRequestTimeout=500
          #設置數(shù)據(jù)傳輸?shù)淖铋L時間
          http.socketTimeout=10000

          然后在 src/main/java/com/itdragon/config 目錄下創(chuàng)建 HttpclientSpringConfig.java 文件

          這里用到了四個很重要的注解

          @Configuration : 作用于類上,指明該類就相當于一個xml配置文件

          @Bean : 作用于方法上,指明該方法相當于xml配置中的

          @PropertySource : 指定讀取的配置文件,引入多個value={"xxx:xxx","xxx:xxx"},ignoreResourceNotFound=true 文件不存在時忽略

          @Value : 獲取配置文件的值,該注解還有很多語法知識,這里暫時不擴展開

          package com.itdragon.config;

          import java.util.concurrent.TimeUnit;
          import org.apache.http.client.config.RequestConfig;
          import org.apache.http.impl.client.CloseableHttpClient;
          import org.apache.http.impl.client.HttpClients;
          import org.apache.http.impl.client.IdleConnectionEvictor;
          import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.context.annotation.PropertySource;
          import org.springframework.context.annotation.Scope;

          /**
          * @Configuration 作用于類上,相當于一個xml配置文件
          * @Bean 作用于方法上,相當于xml配置中的<bean>
          * @PropertySource 指定讀取的配置文件
          * @Value 獲取配置文件的值
          */
          @Configuration
          @PropertySource(value = "classpath:httpclient.properties")
          public class HttpclientSpringConfig {

          @Value("${http.maxTotal}")
          private Integer httpMaxTotal;

          @Value("${http.defaultMaxPerRoute}")
          private Integer httpDefaultMaxPerRoute;

          @Value("${http.connectTimeout}")
          private Integer httpConnectTimeout;

          @Value("${http.connectionRequestTimeout}")
          private Integer httpConnectionRequestTimeout;

          @Value("${http.socketTimeout}")
          private Integer httpSocketTimeout;

          @Autowired
          private PoolingHttpClientConnectionManager manager;

          @Bean
          public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager {
          PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager;
          // 最大連接數(shù)
          poolingHttpClientConnectionManager.setMaxTotal(httpMaxTotal);
          // 每個主機的最大并發(fā)數(shù)
          poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpDefaultMaxPerRoute);
          return poolingHttpClientConnectionManager;
          }

          @Bean // 定期清理無效連接
          public IdleConnectionEvictor idleConnectionEvictor {
          return new IdleConnectionEvictor(manager, 1L, TimeUnit.HOURS);
          }

          @Bean // 定義HttpClient對象 注意該對象需要設置scope="prototype":多例對象
          @Scope("prototype")
          public CloseableHttpClient closeableHttpClient {
          return HttpClients.custom.setConnectionManager(this.manager).build;
          }

          @Bean // 請求配置
          public RequestConfig requestConfig {
          return RequestConfig.custom.setConnectTimeout(httpConnectTimeout) // 創(chuàng)建連接的最長時間
          .setConnectionRequestTimeout(httpConnectionRequestTimeout) // 從連接池中獲取到連接的最長時間
          .setSocketTimeout(httpSocketTimeout) // 數(shù)據(jù)傳輸?shù)淖铋L時間
          .build;
          }
          }

          整合 Redis

          SpringBoot官方其實提供了spring-boot-starter-redis pom 幫助我們快速開發(fā),但我們也可以自定義配置,這樣可以更方便地掌控。Redis 系列教程 : http://www.cnblogs.com/itdragon/category/1122427.html

          首先在src/main/resources 目錄下創(chuàng)建 redis.properties 配置文件設置Redis主機的ip地址和端口號,和存入Redis數(shù)據(jù)庫中的key以及存活時間。這里為了方便測試,存活時間設置的比較小。這里的配置是單例Redis。

          redis.node.host=192.168.225.131
          redis.node.port=6379

          REDIS_USER_SESSION_KEY=REDIS_USER_SESSION
          SSO_SESSION_EXPIRE=30

          在src/main/java/com/itdragon/config 目錄下創(chuàng)建 RedisSpringConfig.java 文件

          package com.itdragon.config;

          import java.util.ArrayList;
          import java.util.List;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.context.annotation.PropertySource;
          import redis.clients.jedis.JedisPool;
          import redis.clients.jedis.JedisPoolConfig;
          import redis.clients.jedis.JedisShardInfo;
          import redis.clients.jedis.ShardedJedisPool;

          @Configuration
          @PropertySource(value = "classpath:redis.properties")
          public class RedisSpringConfig {

          @Value("${redis.maxTotal}")
          private Integer redisMaxTotal;

          @Value("${redis.node.host}")
          private String redisNodeHost;

          @Value("${redis.node.port}")
          private Integer redisNodePort;

          private JedisPoolConfig jedisPoolConfig {
          JedisPoolConfig jedisPoolConfig = new JedisPoolConfig;
          jedisPoolConfig.setMaxTotal(redisMaxTotal);
          return jedisPoolConfig;
          }

          @Bean
          public JedisPool getJedisPool{ // 省略第一個參數(shù)則是采用 Protocol.DEFAULT_DATABASE
          JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisNodeHost, redisNodePort);
          return jedisPool;
          }

          @Bean
          public ShardedJedisPool shardedJedisPool {
          List<JedisShardInfo> jedisShardInfos = new ArrayList<JedisShardInfo>;
          jedisShardInfos.add(new JedisShardInfo(redisNodeHost, redisNodePort));
          return new ShardedJedisPool(jedisPoolConfig, jedisShardInfos);
          }
          }

          Service 層

          在src/main/java/com/itdragon/service 目錄下創(chuàng)建 UserService.java 文件,它負責三件事情

          第一件事情:驗證用戶信息是否正確,并將登錄成功的用戶信息保存到Redis數(shù)據(jù)庫中。

          第二件事情:負責判斷用戶令牌是否過期,若沒有則刷新令牌存活時間。

          第三件事情:負責從Redis數(shù)據(jù)庫中刪除用戶信息。

          這里用到了一些工具類,不影響學習,可以從源碼中直接獲取。

          package com.itdragon.service;

          import java.util.UUID;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import javax.transaction.Transactional;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.context.annotation.PropertySource;
          import org.springframework.stereotype.Service;
          import org.springframework.util.StringUtils;
          import com.itdragon.pojo.ItdragonResult;
          import com.itdragon.pojo.User;
          import com.itdragon.repository.JedisClient;
          import com.itdragon.repository.UserRepository;
          import com.itdragon.utils.CookieUtils;
          import com.itdragon.utils.ItdragonUtils;
          import com.itdragon.utils.JsonUtils;

          @Service
          @Transactional
          @PropertySource(value = "classpath:redis.properties")
          public class UserService {

          @Autowired
          private UserRepository userRepository;

          @Autowired
          private JedisClient jedisClient;

          @Value("${REDIS_USER_SESSION_KEY}")
          private String REDIS_USER_SESSION_KEY;

          @Value("${SSO_SESSION_EXPIRE}")
          private Integer SSO_SESSION_EXPIRE;

          public ItdragonResult userLogin(String account, String password,
          HttpServletRequest request, HttpServletResponse response) {
          // 判斷賬號密碼是否正確
          User user = userRepository.findByAccount(account);
          if (!ItdragonUtils.decryptPassword(user, password)) {
          return ItdragonResult.build(400, "賬號名或密碼錯誤");
          }
          // 生成token
          String token = UUID.randomUUID.toString;
          // 清空密碼和鹽避免泄漏
          String userPassword = user.getPassword;
          String userSalt = user.getSalt;
          user.setPassword;
          user.setSalt;
          // 把用戶信息寫入 redis
          jedisClient.set(REDIS_USER_SESSION_KEY + ":" + token, JsonUtils.objectToJson(user));
          // user 已經(jīng)是持久化對象,被保存在session緩存當中,若user又重新修改屬性值,那么在提交事務時,此時 hibernate對象就會拿當前這個user對象和保存在session緩存中的user對象進行比較,如果兩個對象相同,則不會發(fā)送update語句,否則會發(fā)出update語句。
          user.setPassword(userPassword);
          user.setSalt(userSalt);
          // 設置 session 的過期時間
          jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
          // 添加寫 cookie 的邏輯,cookie 的有效期是關閉瀏覽器就失效。
          CookieUtils.setCookie(request, response, "USER_TOKEN", token);
          // 返回token
          return ItdragonResult.ok(token);
          }

          public void logout(String token) {
          jedisClient.del(REDIS_USER_SESSION_KEY + ":" + token);
          }

          public ItdragonResult queryUserByToken(String token) {
          // 根據(jù)token從redis中查詢用戶信息
          String json = jedisClient.get(REDIS_USER_SESSION_KEY + ":" + token);
          // 判斷是否為空
          if (StringUtils.isEmpty(json)) {
          return ItdragonResult.build(400, "此session已經(jīng)過期,請重新登錄");
          }
          // 更新過期時間
          jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
          // 返回用戶信息
          return ItdragonResult.ok(JsonUtils.jsonToPojo(json, User.class));
          }
          }

          Controller 層

          負責跳轉登錄頁面跳轉

          package com.itdragon.controller;

          import org.springframework.stereotype.Controller;
          import org.springframework.ui.Model;
          import org.springframework.web.bind.annotation.RequestMapping;

          @Controller
          public class PageController {

          @RequestMapping("/login")
          public String showLogin(String redirect, Model model) {
          model.addAttribute("redirect", redirect);
          return "login";
          }

          }

          負責用戶的登錄,退出,獲取令牌的操作

          package com.itdragon.controller;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.PathVariable;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RequestMethod;
          import org.springframework.web.bind.annotation.ResponseBody;
          import com.itdragon.pojo.ItdragonResult;
          import com.itdragon.service.UserService;

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

          @Autowired
          private UserService userService;

          @RequestMapping(value="/login", method=RequestMethod.POST)
          @ResponseBody
          public ItdragonResult userLogin(String username, String password,
          HttpServletRequest request, HttpServletResponse response) {
          try {
          ItdragonResult result = userService.userLogin(username, password, request, response);
          return result;
          } catch (Exception e) {
          e.printStackTrace;
          return ItdragonResult.build(500, "");
          }
          }

          @RequestMapping(value="/logout/{token}")
          public String logout(@PathVariable String token) {
          userService.logout(token); // 思路是從Redis中刪除key,實際情況請和業(yè)務邏輯結合
          return "index";
          }

          @RequestMapping("/token/{token}")
          @ResponseBody
          public Object getUserByToken(@PathVariable String token) {
          ItdragonResult result = ;
          try {
          result = userService.queryUserByToken(token);
          } catch (Exception e) {
          e.printStackTrace;
          result = ItdragonResult.build(500, "");
          }
          return result;
          }
          }

          視圖層

          一個簡單的登錄頁面

          <%@ page language="java" contentType="text/html; charset=UTF-8"
          pageEncoding="UTF-8"%>
          <!doctype html>
          <html lang="zh">
          <head>
          <meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=no" />
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
          <meta http-equiv="X-UA-Compatible" content="IE=8" />
          <title>歡迎登錄</title>
          <link type="image/x-icon" href="images/favicon.ico" rel="shortcut icon">
          <link rel="stylesheet" href="static/css/main.css" />
          </head>
          <body>
          <div class="wrapper">
          <div class="container">
          <h1>Welcome</h1>
          <form method="post" onsubmit="return false;" class="form">
          <input type="text" value="itdragon" name="username" placeholder="Account"/>
          <input type="password" value="123456789" name="password" placeholder="Password"/>
          <button type="button" id="login-button">Login</button>
          </form>
          </div>
          <ul class="bg-bubbles">
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          <li></li>
          </ul>
          </div>
          <script type="text/javascript" src="static/js/jquery-1.10.1.min.js" ></script>
          <script type="text/javascript">
          var redirectUrl = "${redirect}"; // 瀏覽器中返回的URL
          function doLogin {
          $.post("/user/login", $(".form").serialize,function(data){
          if (data.status == 200) {
          if (redirectUrl == "") {
          location.href = "http://localhost:8082";
          } else {
          location.href = redirectUrl;
          }
          } else {
          alert("登錄失敗,原因是:" + data.msg);
          }
          });
          }
          $(function{
          $("#login-button").click(function{
          doLogin;
          });
          });
          </script>
          </body>
          </html>

          HttpClient 基礎語法

          這里封裝了get,post請求的方法

          package com.itdragon.utils;

          import java.io.IOException;
          import java.net.URI;
          import java.util.ArrayList;
          import java.util.List;
          import java.util.Map;
          import org.apache.http.NameValuePair;
          import org.apache.http.client.entity.UrlEncodedFormEntity;
          import org.apache.http.client.methods.CloseableHttpResponse;
          import org.apache.http.client.methods.HttpGet;
          import org.apache.http.client.methods.HttpPost;
          import org.apache.http.client.utils.URIBuilder;
          import org.apache.http.entity.ContentType;
          import org.apache.http.entity.StringEntity;
          import org.apache.http.impl.client.CloseableHttpClient;
          import org.apache.http.impl.client.HttpClients;
          import org.apache.http.message.BasicNameValuePair;
          import org.apache.http.util.EntityUtils;

          public class HttpClientUtil {

          public static String doGet(String url) {// 無參數(shù)get請求
          return doGet(url, );
          }

          public static String doGet(String url, Map<String, String> param) {// 帶參數(shù)get請求
          CloseableHttpClient httpClient = HttpClients.createDefault;// 創(chuàng)建一個默認可關閉的Httpclient 對象
          String resultMsg = "";// 設置返回值
          CloseableHttpResponse response = ;// 定義HttpResponse 對象
          try {
          URIBuilder builder = new URIBuilder(url);// 創(chuàng)建URI,可以設置host,設置參數(shù)等
          if (param != ) {
          for (String key : param.keySet) {
          builder.addParameter(key, param.get(key));
          }
          }
          URI uri = builder.build;
          HttpGet httpGet = new HttpGet(uri);// 創(chuàng)建http GET請求
          response = httpClient.execute(httpGet); // 執(zhí)行請求
          if (response.getStatusLine.getStatusCode == 200) { // 判斷返回狀態(tài)為200則給返回值賦值
          resultMsg = EntityUtils.toString(response.getEntity, "UTF-8");
          }
          } catch (Exception e) {
          e.printStackTrace;
          } finally { // 不要忘記關閉
          try {
          if (response != ) {
          response.close;
          }
          httpClient.close;
          } catch (IOException e) {
          e.printStackTrace;
          }
          }
          return resultMsg;
          }

          public static String doPost(String url) { // 無參數(shù)post請求
          return doPost(url, );
          }

          public static String doPost(String url, Map<String, String> param) {// 帶參數(shù)post請求
          CloseableHttpClient httpClient = HttpClients.createDefault;// 創(chuàng)建一個默認可關閉的Httpclient 對象
          CloseableHttpResponse response = ;
          String resultMsg = "";
          try {
          HttpPost httpPost = new HttpPost(url); // 創(chuàng)建Http Post請求
          if (param != ) { // 創(chuàng)建參數(shù)列表
          List<NameValuePair> paramList = new ArrayList<NameValuePair>;
          for (String key : param.keySet) {
          paramList.add(new BasicNameValuePair(key, param.get(key)));
          }
          UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);// 模擬表單
          httpPost.setEntity(entity);
          }
          response = httpClient.execute(httpPost);// 執(zhí)行http請求
          if (response.getStatusLine.getStatusCode == 200) {
          resultMsg = EntityUtils.toString(response.getEntity, "utf-8");
          }
          } catch (Exception e) {
          e.printStackTrace;
          } finally {
          try {
          if (response != ) {
          response.close;
          }
          httpClient.close;
          } catch (IOException e) {
          e.printStackTrace;
          }
          }
          return resultMsg;
          }

          public static String doPostJson(String url, String json) {
          CloseableHttpClient httpClient = HttpClients.createDefault;
          CloseableHttpResponse response = ;
          String resultString = "";
          try {
          HttpPost httpPost = new HttpPost(url);
          StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
          httpPost.setEntity(entity);
          response = httpClient.execute(httpPost);
          if (response.getStatusLine.getStatusCode == 200) {
          resultString = EntityUtils.toString(response.getEntity, "utf-8");
          }
          } catch (Exception e) {
          e.printStackTrace;
          } finally {
          try {
          if (response != ) {
          response.close;
          }
          httpClient.close;
          } catch (IOException e) {
          e.printStackTrace;
          }
          }
          return resultString;
          }
          }

          Spring 自定義攔截器

          這里是另外一個項目 itdragon-service-test-sso 中的代碼,首先在src/main/resources/spring/springmvc.xml 中配置攔截器,設置那些請求需要攔截

           <!-- 攔截器配置 -->
          <mvc:interceptors>
          <mvc:interceptor>
          <mvc:mapping path="/github/**"/>
          <bean class="com.itdragon.interceptors.UserLoginHandlerInterceptor"/>
          </mvc:interceptor>
          </mvc:interceptors>

          然后在 src/main/java/com/itdragon/interceptors 目錄下創(chuàng)建 UserLoginHandlerInterceptor.java 文件

          package com.itdragon.interceptors;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.util.StringUtils;
          import org.springframework.web.servlet.HandlerInterceptor;
          import org.springframework.web.servlet.ModelAndView;
          import com.itdragon.pojo.User;
          import com.itdragon.service.UserService;
          import com.itdragon.utils.CookieUtils;

          public class UserLoginHandlerInterceptor implements HandlerInterceptor {

          public static final String COOKIE_NAME = "USER_TOKEN";

          @Autowired
          private UserService userService;

          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
          throws Exception {
          String token = CookieUtils.getCookieValue(request, COOKIE_NAME);
          User user = this.userService.getUserByToken(token);
          if (StringUtils.isEmpty(token) || == user) {
          // 跳轉到登錄頁面,把用戶請求的url作為參數(shù)傳遞給登錄頁面。
          response.sendRedirect("http://localhost:8081/login?redirect=" + request.getRequestURL);
          // 返回false
          return false;
          }
          // 把用戶信息放入Request
          request.setAttribute("user", user);
          // 返回值決定handler是否執(zhí)行。true:執(zhí)行,false:不執(zhí)行。
          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 {
          }
          }

          可能存在的問題

          SpringData 自動更新問題

          SpringData 是基于Hibernate的。當User 已經(jīng)是持久化對象,被保存在session緩存當中。若User又重新修改屬性值,在提交事務時,此時hibernate對象就會拿當前這個User對象和保存在session緩存中的User對象進行比較,如果兩個對象相同,則不會發(fā)送update語句,否則,會發(fā)出update語句。

          筆者采用比較傻的方法,就是在提交事務之前把數(shù)據(jù)還原。各位如果有更好的辦法請告知,謝謝!

          參考博客:http://www.cnblogs.com/xiaoluo501395377/p/3380270.html

          檢查用戶信息是否保存

          登錄成功后,進入Redis客戶端查看用戶信息是否保存成功。同時為了方便測試,也可以刪除這個key。

          [root@localhost bin]# ./redis-cli -h 192.168.225.131 -p 6379
          192.168.225.131:6379>
          192.168.225.131:6379> keys *
          1) "REDIS_USER_SESSION:1d869ac0-3d22-4e22-bca0-37c8dfade9ad"
          192.168.225.131:6379> get REDIS_USER_SESSION:1d869ac0-3d22-4e22-bca0-37c8dfade9ad
          "{\"id\":3,\"account\":\"itdragon\",\"userName\":\"ITDragonGit\",\"plainPassword\":,\"password\":,\"salt\":,\"iphone\":\"12349857999\",\"email\":\"itdragon@git.com\",\"platform\":\"github\",\"createdDate\":\"2017-12-22 21:11:19\",\"updatedDate\":\"2017-12-22 21:11:19\"}"

          總結

          1 單點登錄系統(tǒng)通過將用戶信息放在Redis數(shù)據(jù)庫中實現(xiàn)共享Session效果。

          2 Java 配置方式使用四個注解 @Configuration @Bean @PropertySource @Value 。

          3 Spring 攔截器的設置。

          4 HttpClient 的使用。

          5 祝大家圣誕節(jié)快樂!

          源碼: https://github.com/ITDragonBlog/daydayup/tree/master/SpringBoot-SSO

          到這里,基于SpringBoot的單點登錄系統(tǒng)就結束了,有什么不對的地方請指出。


          主站蜘蛛池模板: 国产成人精品一区二三区在线观看| 国产未成女一区二区三区 | 精品视频在线观看一区二区| 人妻互换精品一区二区| 国产色欲AV一区二区三区| 一区二区免费电影| 日韩精品无码一区二区三区| 97精品一区二区视频在线观看| 亚洲一区二区无码偷拍| 国产免费一区二区三区VR| 精品久久国产一区二区三区香蕉 | 精品日韩一区二区三区视频| 亚洲av无码一区二区三区天堂古代| 中文字幕一区二区三匹| 国产婷婷色一区二区三区深爱网| 一区二区在线视频观看| 人妻激情偷乱视频一区二区三区| 国产乱人伦精品一区二区| 国产精品一区二区在线观看| 国产精品 一区 在线| 无码精品视频一区二区三区 | 国产激情视频一区二区三区| 精品国产AV一区二区三区| 无码夜色一区二区三区| 国产福利一区二区在线视频 | 日本免费一区尤物| 一本AV高清一区二区三区| 精品无码av一区二区三区| 亚洲av乱码一区二区三区| av无码精品一区二区三区四区| 日韩精品一区二区三区在线观看| 日本欧洲视频一区| 五十路熟女人妻一区二区 | 国产成人精品第一区二区| 正在播放国产一区| 美女福利视频一区| 成人区精品一区二区不卡亚洲| 久久99精品波多结衣一区| 无码一区二区三区亚洲人妻| 精品国产一区二区三区香蕉| 亚洲欧美日韩中文字幕一区二区三区|