dubbo 存储结构
**树形存储结构**
md5加密
导入的包 为 import org.springframework.util.DigestUtils;
public void saveUser(User user) {
String md5Password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Password).setEmail(user.getPhone());
userMapper.insert(user);
}
}
服务器
服务器:分为服务器硬件 和 服务器软件。在硬件服务器(计算机)上安装了服务器软件,才可以对外提供服务。
(1) 服务器硬件:是指在互联网上具有独立IP地址的计算机,比如我们自己用的计算机也可以作为服务器使用。
(2) 服务器软件:就是一个计算机程序,比如MySQL服务器软件,tomcat服务器软件。服务器软件分为很多类型,比如:ftp服务器,数据库服务器,web服务器软件,邮件服务器等。
WEB服务器
(1) web服务器是指驻留在互联网上的某种类型的计算机程序。当浏览器访问服务器,请求服务器上的文件时,服务器将会处理该请求,并将请求的文件响应给浏览器,并会附带一些信息告诉浏览器如何查看该文件(即文件的类型)
(2) web服务器是可以向 “发出请求的浏览器提供文档” 的程序,比如在访问百度时,其实就是在访问百度的服务器。
tomcat就是一个web服务器软件,是由apache组织提供的一款服务器软件,特点:小巧灵活,免费开源,简单易用。
TOMCAT
tomcat服务器运行需要jdk的支持,版本对应为:
tomcat5 需要jdk4以上支持
tomcat6 需要jdk5以上支持
tomcat7 需要jdk6以上支持
tomcat8 需要jdk7以上支持
启动、关闭tomcat服务器:
通过 [tomcat根目录]\bin\startup.bat 可以启动tomcat服务器;
通过 [tomcat根目录]\bin\shutdown.bat 可以关闭tomcat服务器;
默认端口 8080
修改端口
找到 [tomcat安装目录]/conf/server.xml 文件并打开该文件,将文件中的 69 行的 <Connector>
标签上的 port 属性的值改为 80即可。改完后,保存文件,重新启动服务器
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
cmd 查找进程 杀死进程的方法
打开一个cmd窗口,通过 netstat -ano 命令查看当前系统中活动的进程,找到80端口对应的进程编号(PID),根据进程编号将进程结束即可!
执行命令
taskkill /f /pid 进程编号
get提交和post提交的区别
主要区别体现在请求参数传输过程的不相同
GET提交:
- 将数据通过问号拼接在地址栏URL地址的后面,相对非常不安全。
- 将数据拼接在地址栏URL地址的后面,数据量是有限制的,通常不能超过1KB或者4KB。
POST提交:(form)
- POST提交是通过请求实体将数据提交给服务器,不会显示在地址栏上,因此相对更加安全。
- POST提交通过请求实体提交数据,数据量理论上是没有限制的。
Request
request是代表HTTP请求信息的对象,response是代表HTTP响应信息的对象。
当浏览器发请求访问服务器中的某一个Servlet时,服务器将会调用Servlet中的service方法来处理请求。在调用service方法之前会创建出request和response对象。
在请求处理完,响应结束时,服务器会销毁request和response对象
请求参数
所谓的请求参数,就是浏览器发送给服务器的数据(不区分请求方式),例如:通过表单向服务器提交的用户名、密码等,或者在超链接后面通过问号提交的数据,都是请求参数。
http://localhost/day10/TestParam?user=zhangsan&pwd=123&like=篮球&like=足球
获取请求参数
(1)request.getParameter(String paramName)
– 根据请求参数的名字获取对应的参数值,返回值是一个字符串;
– 如果一个参数有多个值,该方法只会返回第一个值。
– 如果获取的是一个不存在的参数,返回值为null
(2)request.getParameterValues(String paramName)
– 根据请求参数的名字获取该名字对应的所有参数值组成的数组,返回值是一个字符串数组,其中包含了这个参数名对应的所有参数值
– 如果获取的是一个不存在的参数,返回值为null
实现求请转发
(1)转发是一次请求,一次响应
(2)请求转发前后,浏览器的地址栏地址不会发生变化。(浏览器–访问–> A --转发–> B,地址栏地址始终指向A的地址)
(3)请求转发前后的request对象是同一个(转发前在A中的request和转发到B后,B中的request对象和A中的request对象是同一个。基于这一点,可以通过request从A带数据到B)
(4)请求转发前后的两个资源必须属于同一个Web应用,否则将无法进行转发。(A–转发–>B,A和B必须属于同一个Web应用!)
request.getRequestDispatcher(url地址/转发到资源的地址).forward(req, res);
作为域对象使用
request在实现转发时,通过request.setAttribute方法和request.getAttribute方法带数据到目的地时,就是通过request对象中的map集合带数据,这个request对象上的map集合以及request对象所在的范围即称之为是一个域对象。
如果一个对象具备可以被访问的范围,通过这个对象上的map集合可以在整个范围内实现数据的共享。这样的对象就叫做域对象。
在request对象上提供了往域对象(map)中存数据的方法以及取数据的方法
request.setAttribute(String attrName, Object attrValue);
-- 往request域中存入一个域属性,属性名(key)只能是字符串,属性值(value)可以是任意类型。
request.getAttribute(String attrName);
-- 根据属性名(key)获取对应的属性值(value)。返回的是一个Object类型的对象。
request域对象所具备的三大特征:
**生命周期:**在服务器调用Servlet程序的service方法之前,会创建代表请求的request对象,在请求处理完,响应结束时,会销毁request对象。
**作用范围:**在一次请求范围内,都可以获取到同一个request对象。
**主要功能:**和请求转发配合使用,从Servlet带数据到JSP(带数据到目的地)
Resonse
response是代表HTTP响应信息的对象。
1.向客户端发送数据
PrintWriter out = response.getWriter();
由于服务器在通过response获取的流发送数据时,默认使用iso8859-1编码,而这个编码中没有中文字符,所以在通过response获取的流发送中文数据时,会出现乱码问题。
解决方法是:在响应数据之前,通知服务器使用utf-8发送数据。
/* 通知服务器在响应数据时,使用utf-8编码
* 也能通知浏览器使用utf-8接收服务器发送的数据 */
response.setContentType( "text/html;charset=utf-8" );
PrintWriter out = response.getWriter();
out.write( "你好" );
实现重定向
当浏览器向服务器发请求访问某一个资源A,资源A在响应时通知浏览器需要再进一步请求才能获取到对应的资源,浏览器再次发请求访问服务器中的资源B,最终由资源B响应浏览器要获取的资源,这个过程叫做重定向。
(1)重定向是两次请求、两次响应
(2)重定向前后,浏览器的地址栏地址会发生变化。(因为两次请求都是通过浏览器发起,浏览器知道这个跳转的过程,因此地址栏地址会变化)
(3)重定向前后的request对象不是同一个(因为重定向是两次请求,服务器会根据两次请求创建两个不同的request对象,request对象不是同一个,也就不能在重定向时通过request带数据到目的地。)
(4)重定向前后的两个资源可以是来自不同的web应用,甚至可以是来自不同的服务器。(进行跳转的两个资源之间没有限制)
response.sendRedirect(所重定向到资源的URL地址);
jar 包的插入 在不知道坐标的情况下 可以访问如下网址 访问
http://mvnrepository.com
3、示例:添加c3p0的jar包的坐标到项目中
-
访问上面其中的一个网址,在搜索框中搜索 “c3p0”
-
在搜索出来的内容中,选择所需要的版本并点击版本,查看该版本的c3p0
jar包所对应的坐标: -
将坐标直接拷贝到项目的pom.xml文件中即可:
-
Cookie Session
什么是会话
当浏览器发请求访问服务器开始,一直到访问服务器结束,浏览器关闭为止,这期间浏览器和服务器之间产生的所有请求和响应加在一起,就称之为浏览器和服务器之间的一次会话。
cookie 工作原理
- Cookie是将会话中产生的数据保存在客户端,是客户端技术。
- Cookie是基于两个头进行工作的:分别是Set-Cookie响应头和Cookie请求头
- 通过Set-Cookie响应头将cookie从服务器端发送给浏览器,让浏览器保存到内部;而浏览器一旦保存了cookie,以后浏览器每次访问服务器时,都会通过cookie请求头,将cookie信息再带回服务器中。在需要时,在服务器端可以获取请求中的cookie中的数据,从而实现某些功能。
cookie API
1、创建Cookie对象
Cookie c = new Cookie(String name, String value);
// 创建cookie的同时需要指定cookie的名字和cookie要保存的值
2、将Cookie添加到response响应中
response.addCookie( Cookie c );
// 将cookie添加到响应中,由服务器负责将cookie信息发送给浏览器,再由浏览器保存到内部(可以多次调用该方法,添加一个以上的cookie)
3、获取请求中的所有cookie对象组成的数组
// cookie的API中没有提供直接删除cookie的方法,可以通过别的方式间接删除cookie
// 删除名称为cart的cookie:可以向浏览器再发送一个同名的cookie(即名称也叫做cart),并设置cookie的最大生存时间为零,由于浏览器是根据cookie的名字来区分cookie,如果前后两次向浏览器发送同名的cookie,后发送的cookie会覆盖之前发送的cookie。而后发送的cookie设置了生存时间为零,因此浏览器收到后也会立即删除!
//创建一个名称为cart的cookie
Cookie c = new Cookie("cart", "");
//设置cookie的最大生存时间为零
c.setMaxAge( 0 );
//将cookie添加到响应中,发送给浏览器
response.addCookie( c );
out.write( "成功删除了名称为cart的cookie..." );
5、Cookie的常用方法
cookie.getName(); // 获取cookie的名字 返回值字符串
cookie.getValue(); // 获取cookie中保存的值
cookie.setValue(); // 设置/修改cookie中保存的值(没有setName方法,因为cookie的名字无法修改)
cookie.setMaxAge(); //设置cookie的最大生存时间
//创建一个Cookie对象,将商品信息保存到cookie中
Cookie cookie = new Cookie( "cart", prod );
//设置cookie的最大生存时间, **单位:秒**
cookie.setMaxAge( 60*60*24 );
//将cookie对象添加到response响应中
response.addCookie( cookie );
---------------
//实现cookie的共享
/**
* 1.url地址:http://www.jt.com/user/doLogin?r=0.04360522021726099
* 2.参数: {username:_username,password:_password},
* 3.返回值结果: SysResult
*
* 需求1: 将cookie名称为 "JT_TICKET"数据输出到浏览器中,要求7天超时.
* 并且实现"jt.com"数据共享
*
* Cookie特点:
* 1.浏览器中只能查看当前网址下的Cookie信息
* 2.doMain 表示cookie共享的策略
* doMain:www.jd.com 当前的Cookie数据只能在当前域名中使用
* doMain:.jd.com 当前Cookie是共享的可以在域名为jd.com结尾的域名中共享.
*
* * * */
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
//完成用户登录操作 之后获取ticket密钥信息
String ticket = userService.doLogin(user);
if(StringUtils.isEmpty(ticket)){
//如果为null,则说明用户名或密码有问题
return SysResult.fail();
}
//1.创建Cookie对象
Cookie cookie = new Cookie("JT_TICKET",ticket);
//2.设定cookie存活的时间 value=-1 当用户关闭会话时,cookie删除
//2.设定cookie存活的时间 value= 0 立即删除cookie
//2.设定cookie存活的时间 value= >0 设定cookie超时时间
cookie.setMaxAge(7*24*60*60);
//3.在jt.com的域名中实现数据共享.
cookie.setDomain("jt.com");
cookie.setPath("/"); //一般情况下都是/ 表示/以后的路径都能访问到该cookie
//4.将数据保存到浏览器中
response.addCookie(cookie);
return SysResult.success();
}
session
获取session对象:
request.getSession()
// 获取一个session对象;如果在服务器内部有当前浏览器对应的session,则直接返回该session对象;如果没有对应session,则会创建一个新的session对象再返回;
Session是一个域对象,因此session中也提供了存取数据的方法。
session.setAttribute(String attrName, Object attrValue);
// 往session域中添加一个域属性,属性名只能是字符串类型,属性值可以是任意类型。
session.getAttribute(String attrName);
// 根据属性名获取域中的属性值,返回值是一个Object类型
特征:
(1)生命周期:
**创建session:**第一次调用request.getSession()方法时,会创建一个session对象。(当浏览器在服务器端没有对应的session时,调用request.getSession()方法服务器会创建一个session对象。)
销毁session:
-
超时销毁:默认情况下,当超过30分钟没有访问session,session就会超时销毁。(30分钟是默认时间,可以修改,但不推荐修改)
-
自杀:调用session的invalidate方法时,会立即销毁session。
-
意外身亡:当服务器非正常关闭时(硬件损坏,断电,内存溢出等导致服务器非正常关闭),session会随着服务器的关闭而销毁;
当服务器正常关闭,在关闭之前,服务器会将内部的session对象序列化保存到服务器的work目录下,变为一个文件。这个过程叫做session的钝化(序列化);再次将服务器启动起来,钝化着的session会再次回到服务器,变为服务器中的对象,这个过程叫做session的活化(反序列化)。
**(2)作用范围:**在一次会话范围内(获取到的都是同一个session对象)
**(3)主要功能:**在整个会话范围内实现数据的共享
获取不到之前的session的问题
session是基于Cookie工作的。
在服务器创建一个session后,会为session分配一个独一无二的编号,称之为session的id,在此次响应时,服务器会将session的id以一个名称为JSESSIONID的cookie发送给浏览器保存到浏览器内部。
由于保存sessionid的cookie默认是会话级别的cookie,在浏览器关闭后,cookie会跟着销毁,sessionid也丢失了。因此下次访问服务器,没有session的id就获取不到之前的session。也获取不到session中的商品信息
解决方法:我们可以创建一个名称为JSESSIONID的cookie,其中保存session的ID,并设置cookie的最大存活时间,让cookie保存到硬盘上(即使浏览器关闭,cookie也不会销毁),这样下次访问服务器时,还可以将sessionid带给服务器,服务器可以通过sessionid获取到之前的session。 从session中获取到商品信息
事物隔离级别
1、READ UNCOMMITTED(读未提交数据)
安全性最差,可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等)
但性能最好(不使用!!)
2、READ COMMITTED(读已提交数据)(Oracle默认)
安全性较差
性能较好
可以防止脏读,但不能防止不可重复读,也不能防止幻读;
3、REPEATABLE READ(可重复读)(MySQL默认)
安全性较高
性能较差
可以防止脏读和不可重复读,但不能防止幻读问题;
4、SERIALIZABLE(串行化)
安全性最高,不会出现任何并发问题,因为它对同一数据的访问是串行的,非并发访问;
性能最差;(不使用!!)
MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读
mybatis 中的占位符
在mybatis中占位符有两个,分别是 #{}
占位符 和 ${}
占位符:
-
#{}:
相当于JDBC中的问号(?)占位符,是为SQL语句中的参数值进行占位,大部分情况下都是使用#{}占位符; 并且当#{}占位符是为字符串或者日期类型的值进行占位时,在参数值传过来替换占位符的同时,会进行转义处理(在字符串或日期类型的值的两边加上单引号) -
${}
:是为SQL片段进行占位,将传过来的SQL片段直接拼接在${}占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题)
mybatis foreach
示例:
<!-- 练习14: 根据员工的id批量删除员工信息
delete from emp where id in (1,3,5,7)
collection: 如果传的参数仅仅是一个数组或者List集合, collection可以指定为
array或list; 如果传的是多个参数,用map封装,collection则指定为map中的key
open: 指定生成的SQL片段以什么符号开始
close: 指定生成的SQL片段以什么符号结束
item: 指定变量接收数组或集合中的元素
separator: 指定一个间隔符, 在将数组或集合中的每个元素拼接到SQL片段之后,
在后面拼接一个间隔符
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="array" open="(" item="id" separator="," close=")">
#{id}
</foreach>
</delete>
mybatis 单独实现 数据读取
/** 练习1(快速入门): 查询emp表中的所有员工, 返回一个List<Emp>集合
* @throws IOException */
@Test
public void findAll() throws IOException {
//1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources
.getResourceAsStream("mybatis-config.xml");
//2.通过配置信息获取一个SqlSessionFactory工厂对象
SqlSessionFactory fac =
new SqlSessionFactoryBuilder().build( in );
//3.通过工厂获取一个SqlSession对象
SqlSession session = fac.openSession();
//4.通过namespace+id找到要执行的sql语句并执行sql语句
List<Emp> list = session
.selectList("EmpMapper.findAll");
//5.输出结果
for(Emp e : list) {
System.out.println( e );
}
}
--------------------------
//`mybatis-config文件详细配置如下:`
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- MyBatis的全局配置文件 -->
<configuration >
<!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) -->
<environments default="develop">
<environment id="develop">
<!-- 1.1.配置事务管理方式:JDBC/MANAGED
JDBC:将事务交给JDBC管理(推荐)
MANAGED:自己管理事务
-->
<transactionManager type="JDBC"></transactionManager>
<!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED
JNDI:已过时
POOLED:使用连接池(推荐)
UNPOOLED:不使用连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标签导入 -->
<mappers>
<mapper resource="EmpMapper.xml"/>
</mappers>
</configuration>
工厂解耦模式
程序中new对象的方式造成了这种程序之间的依赖程度提升,即提升了程序之间的耦合性。
使用工厂+配置文件+接口解耦代码如下:
package com.tedu.factory;
import java.io.InputStream;
import java.util.Properties;
/**
* ---------------------------------------------------------
* Bean: 可重用组件(计算机英语)
* JavaBean:使用Java语言编写的可重用组件,例如:service层、dao层等
* JavaBean:通常分为业务Bean和实体Bean
* 业务Bean:处理业务逻辑,service层、dao层
* 实体Bean:封装数据,例如,为了封装员工信息而编写的Emp实体类.
* ---------------------------------------------------------
* 解除耦合:
* (1)需要提供配置文件,在配置文件中配置service和dao的实现类
* 配置内容为:唯一标识=实现类的全限定类名(key=value结构)
* (2)通过工厂读取配置文件中配置的全限定类名,利用反射创建对象。
* xml配置文件、properties配置文件
*/
public class BeanFactory {
//声明一个Properties对象,在静态代码块中对其进行初始化
private static Properties prop;
static {
try {
//为prop进行实例化
prop = new Properties();
//获取配置文件的流对象
InputStream in = BeanFactory.class.getClassLoader()
.getResourceAsStream("config.properties");
//将配置文件中的内容读取到Properties对象中
prop.load( in );
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("初始化Properties对象失败!");
}
}
/**
* 根据config.xml文件中的key获取对应class类的实例
* @param key
* @return
*/
public static Object getBean(String key) {
Object bean = null;
try {
String className = prop.getProperty( key );
bean = Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
在源码目录下创建一个config.properties文件,文件内容配置如下:
EmpService=com.tedu.service.EmpServiceImpl
EmpDao=com.tedu.dao.EmpDaoImpl
将EmpController类中通过 “new对象的形式获取了EmpService接口子类的实例” 以及在EmpServiceImpl类中通过 “new对象的形式获取了EmpDao接口子类的实例” 改为使用BeanFactory工厂获取Service和Dao层的实例。如下:
获取Service接口的子类实例
* ——这里使用new对象的方式造成了程序之间的耦合性提升 */
//private EmpService service = new EmpServiceImpl();
private EmpService service = (EmpService)BeanFactory.getBean("EmpService");
/* 获取Dao接口的子类实例
* ——这里使用new对象的方式造成了程序之间的耦合性提升 */
//private EmpDao dao = new EmpDaoImpl();
private EmpDao dao = (EmpDao)BeanFactory.getBean( "EmpDao" );
spring ioc 控制反转
把创建对象的权利交给框架。也就是指将对象的创建、对象的存储、对象的管理交给了spring容器。
核心配置文件:创建xml 文件 applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将EmpService接口的实现类的实例交给spring创建 -->
<bean id="empService" class="com.tedu.service.EmpServiceImpl"></bean>
<!-- 将EmpDao接口的实现类的实例交给spring创建 -->
<bean id="empDao" class="com.tedu.dao.EmpDaoImpl"></bean>
</beans>
通过下面代码 获取bean
public class TestSpring {
/**
* 使用spring的IOC解决程序中的耦合问题
*/
@Test
public void testIOC() {
//获取spring的核心容器对象
ApplicationContext ac =
new ClassPathXmlApplicationContext(
"applicationContext.xml");
//通过spring的核心容器获取EmpService接口的子类实例
EmpService service = (EmpService) ac.getBean("empService");
EmpDao dao = (EmpDao) ac.getBean("empDao");
System.out.println( service );
System.out.println( dao );
}
}
单实例 多实例
在Spring容器中管理的Bean对象的作用域,可以通过scope属性或用相关注解指定其作用域。
spring 执行流程
(1)
.用户发送请求 至 前端控制器(DispatcherServlet);
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心
(2)
.前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping)
处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;
(3)
.前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller–> service --> Dao --> 数据库)
Controller执行完成后返回ModelAndView,
提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)
处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);
(4)
.前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)
视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面
(5)
.前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);
前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。
mvc 的请求转发 和重定向
/* 测试请求转发(forward) */
@RequestMapping("testForward")
public String testForward(){
System.out.println("测试请求转发(forward)...");
return "forward:hello";
}
/* 测试请求重定向(redirect) */
@RequestMapping("testRedirect")
public String testRedirect(){
System.out.println("测试请求重定向(redirect)...");
return "redirect:hello";
}
springboot 中优化掉了web.xml 定义web.xml的方法
实现 WebMvcConfigurer 接口
package com.jt.handler;
import com.jt.pojo.User;
import com.jt.util.CookieUtil;
import com.jt.util.ObjectMapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//拦截器的类(业务) 拦截器的配置文件(拦截什么请求)
@Component
public class UserInterceptor implements HandlerInterceptor {
private static final String TICKET = "JT_TICKET";
private static final String JTUSER = "JT_USER";
@Autowired
private JedisCluster jedisCluster;
/**
* 实现pre的方法
* 返回值说明:
* return false 表示拦截 需要配合重定向一齐使用
* return ture 表示放行
* 需求1: 如果用户没有登录,则重定向到系统登录页面
* 判断条件: 如何判断用户是否登录. 1.检查Cookie中是否有记录 2.Redis中是否有记录.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Cookie cookie = CookieUtil.getCookieByName(request, TICKET);
if(cookie != null){ //不为null.则表示用户可能登录.
String ticket = cookie.getValue(); //cookie中存储的是Redis的key ticket密钥
if(jedisCluster.exists(ticket)){
//如果redis中的数据存在,则说明用户已经登录.可以放行请求.
//获取真实的用户信息
String userJSON = jedisCluster.get(ticket);
//将json转化为对象
User user = ObjectMapperUtil.toObject(userJSON, User.class);
request.setAttribute(JTUSER, user);
return true;
}else{
//Cookie中的记录与Redis中的记录不一致.应该删除Cookie中的数据.
CookieUtil.deleteCookie(TICKET, "/", "jt.com",response);
}
}
response.sendRedirect("/user/login.html");
return false; //表示拦截
}
}
springboot 定义拦截器
有三种 拦截器 分别为 preHandle postHandle afterHandle 拦截的示意图
- 首先在xml中 编辑拦截器配置文件
- 编辑拦截器配置文件
package com.jt.handler;
import com.jt.pojo.User;
import com.jt.util.CookieUtil;
import com.jt.util.ObjectMapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//拦截器的类(业务) 拦截器的配置文件(拦截什么请求)
@Component
public class UserInterceptor implements HandlerInterceptor {
private static final String TICKET = "JT_TICKET";
private static final String JTUSER = "JT_USER";
@Autowired
private JedisCluster jedisCluster;
/**
* 实现pre的方法
* 返回值说明:
* return false 表示拦截 需要配合重定向一齐使用
* return ture 表示放行
* 需求1: 如果用户没有登录,则重定向到系统登录页面
* 判断条件: 如何判断用户是否登录. 1.检查Cookie中是否有记录 2.Redis中是否有记录.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Cookie cookie = CookieUtil.getCookieByName(request, TICKET);
if(cookie != null){ //不为null.则表示用户可能登录.
String ticket = cookie.getValue(); //cookie中存储的是Redis的key ticket密钥
if(jedisCluster.exists(ticket)){
return true;
}else{
//Cookie中的记录与Redis中的记录不一致.应该删除Cookie中的数据.
CookieUtil.deleteCookie(TICKET, "/", "jt.com",response);
}
}
response.sendRedirect("/user/login.html");
return false; //表示拦截
}
}
ThreadLocal 介绍
说明:如果利用Request对象的方式进行数据的传参,一般只能在Controller中进行动态的数据接收.
如果在业务执行过程中需要该数据,则通过参数的形式继续向下传递.导致接口方法中的参数个数较多.
虽然该写法没有任何的问题. 该操作是否可以优化???
ThreadLocal
名字: 本地线程变量
作用: 在当前线程内,实现数据的共享.
编辑 ThreadLocal 工具 API
package com.jt.util;
import com.jt.pojo.User;
public class UserThreadLocal {
//1.定义本地线程变量!!!!!
private static ThreadLocal<User> threadLocal = new ThreadLocal<>();
//ThreadLocal<Map>
//2.定义数据新增的方法
public static void set(User user){
threadLocal.set(user);
}
//3.获取数据
public static User get(){
return threadLocal.get();
}
//4.移除方法 使用threadLocal时切记将数据移除.否则极端条件下,容易产出内存泄露的问题
public static void remove(){
threadLocal.remove();
}
//实现数据的移除
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserThreadLocal.remove();
}
}
将数据保存到 ThreadLocal中
参数接受 说明
js表单数据
接受的 pojo
用 order接收数据
@RequestMapping("/submit")
@ResponseBody
public SysResult submit(Order order){
//利用拦截器的方式赋值.
Long userId = UserThreadLocal.get().getId();
order.setUserId(userId);
//1.完成订单入库,并且返回orderId
String orderId = orderService.saveOrder(order);
return SysResult.success(orderId);
}