redis概念和下载

1.关系型数据库和非关系型数据库

  • redis是一款高性能的NOSQL系列的非关系性数据库

  • NOSQL和关系型数据库的对比

    1. 优点

      1)成本:nosql数据库简单易部署,相比关系型数据库价格便宜

      2)查询速度:nosql数据库将数据存储在缓存之中,关系型数据库将数据存储在硬盘中,所以nosql查询速度要快

      3)存储数据的格式:nosql的存储格式是key:value形式、文档、图片等,所以可以存储基础类型以及对象或者是集合等格式,而数据库则只支持基础类型

      4)扩展性:关系型数据库由类似join这样的多表查询机制的限制,导致扩展较难

    2. 缺点

      1)维护的工具资料有限,因为nosql是新技术

      2)不提供对sql的支持

      3)不提供关系型数据库对事物的处理

  • 非关系型数据库的优势

    1)性能nosql是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过sql层的解析,所以性能非常高

    2)可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以容易水平扩展

  • 关系型数据库的优势

    1)复杂查询可以用sql语句方便的在一个表和多个表之间查询

    2)事务支持使得对于安全性能很高的数据访问要求得以实现

  • 总结

    在通常情况下将数据存储在关系型数据库中,在nosql的数据库中备份存储关系数据库的存储

2.什么是redis

  • redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s,且redis通过提供多种键值数据类型来适应不同场景下的存储需求。
  • 目前为止redis支持的键值数据类型如下:
    1. 字符串类型 String
    2. 哈希类型 hash
    3. 列表类型 list
    4. 集合类型 set
    5. 有序集合类型 sortedset
  • redis的应用场景
    1. 缓存(数据查询、短链接、新闻内容、商品内容等)
    2. 聊天室的在线好友列表
    3. 任务队列(秒杀、抢购、12306等)
    4. 应用排行榜
    5. 网站访问统计
    6. 数据过期处理(可以精确到毫秒)
    7. 分布式集群架构中的session分离

3.redis下载安装

Windows版本下载地址:https://github.com/MicrosoftArchive/redis/releases

解压后可直接使用

  • redis.windows.conf:配置文件
  • redis-cli.exe:redis的客户端
  • redis-server.exe:redis的服务器端

使用:先启动服务器,然后启动客户端,输入命令存储

注册时异步检测用户名是否已经存在

需求

  • 在注册页面中,当用户输入用户ID后,客户端判断用户ID是否以及存在。
  • 即:当文本输入框失去焦点后,发送Ajax请求,查询数据库是否存在该用户名。如果存在:则提示此用户太受欢迎,请更换一个名字;如果不存在,则提示信息可以用

实现

注册页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>regist</title>
<script src="js/jquery-3.5.1.min.js"> </script>
<script>
//入口函数
$(function () {
//给用户名输入框绑定blur事件
$("#username").blur(function () {
//使用jQuery对象获取输入框内容
var username = $(this).val();
//发送Ajax请求
//期望服务器返回的数据格式:{"userExist":true,"msg":"此用户太受欢迎,请更换一个名字"}
// {"userExist":false,"msg":"用户名可用"}
$.get("findUserServlet",{"username":username},function (data) {
if (data.userExist == false){
//设置span标签的属性
$("#userspan").css("color","green");
$("#userspan").html(data.msg);
}else{
$("#userspan").css("color","red");
$("#userspan").html(data.msg);
}
},"json");
});
});
</script>
</head>
<body>
<form action="/login"method="post">
<input type="text" id="username" name="username"placeholder="请输入用户名">
<span id="userspan"></span>
<br><br>
<input type="text"name="password"placeholder="请输入密码"><br><br>
<input type="submit"value="登录">
</form>
</body>
</html>

判断逻辑findUserServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@WebServlet("/findUserServlet")
public class findUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收用户数据
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
Map<String,Object> map = new HashMap<String, Object>();
//在项目中hxx实际上是查询数据库是否已经存在该用户名
if ("hxx".equals(username)){
map.put("userExist",true);
map.put("msg","此用户太受欢迎,请更换一个名字");
}else {
map.put("userExist",false);
map.put("msg","用户名可用");
}
//将map转换为json字符串
ObjectMapper objectMapper = new ObjectMapper();
//传输给客户端
objectMapper.writeValue(response.getWriter(),map);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}

JSON语法和解析器

1.基本概念

  • JavaScript对象表示法 Javascript Object Notation
  • json现在多用于存储和交换文本信息的语法
  • 进行数据的传输
  • json比XML更小、更快、更易解析

2.语法

  1. 基本规则
    • 数据在名称/值对中:json数据由键值对构成。
      1. 键用单/双引号引起,也可以不使用;
      2. 值的取值类型
        • 数字(整数或浮点数)
        • 字符串(双引号)
        • 逻辑值(true或false)
        • 数组(在方括号中) {“Person”:[{ },{ }….]}
        • 对象 {“address”:{“province”:”陕西”…}}
        • null
    • 数据由逗号隔开:多个键值对由都好分隔
    • 花括号保存对象:使用{}定义json格式
    • 方括号保存数组:[]
  2. 获取数据
    • json对象.键名
    • json对象[“键名”]
    • 数组对象[索引]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script>
//定义基本格式
var person = {"name": "hxx", "age": 20, "gender": true};
//获取person的所有键和值
for (let personKey in person) {
alert(personKey+":"+person[personKey]);
//alert(person.personKey);//这种方式不能正确获取,因为personKey是字符串形式"name",person.personKey相当于person."name"
}
//获取name
alert(person.name);
alert(person["name"]);

//嵌套格式
var persons = {
"persons": [
{"name": "hxx", "age": 20},
{"name": "qzy", "age": 20}
]
};
var ps = persons.persons;
for (let i = 0; i < ps.length; i++) {
var p = ps[i];
for (let pKey in p) {
alert(pKey+":"+ p[pKey]);
}
}
alert(persons.persons[1].name);

var ps = [
{"name": "hxx", "age": 20},
{"name": "qzy", "age": 20}
];
for (let i = 0; i < ps.length; i++) {
var p = ps[i];
for (let pKey in p) {
alert(pKey+":"+ p[pKey]);
}
}
alert(ps[1].name);
</script>

3.json数据和Java对象的相互转换

3.1 Java对象转换为json对象

转换核心对象ObjectMapper的转换方法:

  1. writeValue(参数1,obj)

        参数1:
             File:将obj对象转换为json字符串,并保存到指定文件中
             Writer:将json字符串填充到字符输出流中
             OutputStream:将json字符串填充到字节输出流中
  2. writeValueAsString(obj)转换为json字符串

注解

  1. @JsonIgnore //转换成json对象时忽略该属性

  2. @JsonFormat:属性值格式化

    @JsonFormat(pattern = “yyyy-MM-dd”)

复杂Java对象转换

  1. List:数组
  2. Map:对象格式一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class JacksonTest {
@Test
public void test1() throws IOException {
//创建Person对象
Person person = new Person();
person.setAge(20);
person.setName("hxx");
person.setBirthday(new Date());
//创建Jackson核心对象
ObjectMapper objectMapper = new ObjectMapper();

String json = objectMapper.writeValueAsString(person);
//{"name":"hxx","age":20,"birthday":"2021-03-30"}
System.out.println(json);//{"name":"hxx","age":20}
//将数据写到a.txt中
objectMapper.writeValue(new File("a.txt"),person);

Person p1 = new Person();
p1.setName("张三");
p1.setAge(10);
p1.setBirthday(new Date());

List<Person> list = new ArrayList<Person>();
list.add(person);
list.add(p1);
String asString = objectMapper.writeValueAsString(list);
//[{"name":"hxx","age":20,"birthday":"2021-03-30"},{"name":"张三","age":10,"birthday":"2021-03-30"}]
System.out.println(asString);

Map<String,Object> map = new HashMap<String, Object>();
map.put("name","hxx");
map.put("age",20);
String s = objectMapper.writeValueAsString(map);
//{"name":"hxx","age":20}
System.out.println(s);
}
}

3.2json对象转换为Java对象

转换核心对象ObjectMapper的转换方法:

  1. readValue(json字符串,Class)
1
2
3
4
5
6
7
8
9
@Test
public void test2() throws JsonProcessingException {
//初始化json字符串
String json = "{\"name\":\"hxx\",\"age\":20,\"birthday\":\"2021-03-30\"}";
//创建ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(json, Person.class);
System.out.println(person);
}

AJAX-JQuery实现方式

1.AJAX基本概念

  • ASynchronous Javascript And XML 异步的JavaScript和XML
  • 异步和同步:客户端和服务器端相互通信的基础上
    • 异步:客户端必须等待服务器端的响应。在等待期间客户端不能做其他操作
    • 同步:客户端不需要等待服务器端的响应。在服务器处理请求的过程中,客户端可以进行其他的操作
  • Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术
  • 通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网站的某部分进行更新。传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面。

2.实现方式

2.1原生的JS实现方式

  • html中script实现步骤

    创建XMLHttpRequest对象,用于在后台和服务器交换数据

    建立连接

    发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="发送异步请求" onclick="fun()">
<input type="text"><!--当发送异步请求时客户端输入框可以正常输入,同步请求时要等到服务器处理完才可以操作输入框-->
<span id="myDiv">hxxxx</span>

<script>
//定义方法

function fun() {
var xmlhttp;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
/*建立连接
* 参数:
* 1.请求方式:GET、POST
* get请求参数在URL后面拼接,send方法为空参
* post方式请求参数在send方法中定义
* xmlhttp.send("username=hxx&id=1");
* 2.请求的URL
* 3.同步或异步请求:true(异步) false(同步)
* */
xmlhttp.open("GET","ajaxServlet?username=hxx",true);
//发送请求
xmlhttp.send();
//响应

xmlhttp.onreadystatechange=function()
{
//当 readyState 等于 4 且状态为 200 时,表示响应已就绪:
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerText=xmlhttp.responseText;
alert(xmlhttp.responseText)
}
}
}
</script>
</body>
</html>
  • 服务器资源ajaxServlet接收参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@WebServlet("/ajaxServlet")
public class ajaxServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收参数
String username = request.getParameter("username");
//假设处理时间5秒,观察客户端的输入框是否可以输入数据:异步可以、同步不可以
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印参数
System.out.println(username);
//响应
response.getWriter().write("hello:"+username);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}

2.2Jquery实现方式

  1. $.ajax()
    • 语法:$.ajax(url,[settings]) ,一般情况下写成 $.ajax({键值对})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JqueryAjax</title>
<script src="js/jquery-3.5.1.min.js"> </script>
<script>
function fun() {
//使用$.ajax()发送异步请求
$.ajax(
{
url: "ajaxServlet", //请求路径
type: "POST", //请求方式
data:{ "username":"hxx","age":"20"},//传递的数据
success:function (Data) {//响应成功后的回调函数,Data是服务器的响应数据
alert(Data);
},
error:function () {
alert("出错啦");//表示如果请求响应出现错误,会执行此回调函数
},
data_type:"text"//表示接收到的响应数据的格式
}
);
}
</script>
</head>
<body>
<input type="button" value="发送异步请求" onclick="fun()">
<input type="text"><!--当发送异步请求时客户端输入框可以正常输入,同步请求时要等到服务器处理完才可以操作输入框-->
</body>
</html>
  1. $.get()

    语法:$.get(url,[data],[callback],[type]) 请求路径、请求参数、回调函数、响应结果的类型

1
2
3
4
5
6
7
8
<script>
//定义方法
function fun() {
$.get("ajaxServlet",{"username":"hxx","age":"20"},function (data) {
alert(data);
},"text");
}
</script>
  1. $.post()
1
2
3
4
5
6
7
8
<script>
//定义方法
function fun() {
$.get("ajaxServlet",{"username":"hxx","age":"20"},function (data) {
alert(data);
},"text");
}
</script>

JQuery基础使用

1. 概念

  1. 概念: 一个JavaScript框架。简化JS开发

    • jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨 是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。

    • JavaScript框架:本质上就是一些js文件,封装了js的原生代码而已

2.快速入门

  1. 下载JQuery

    目前jQuery有三个大版本:
    1.x:兼容ie678,使用最为广泛的,官方只做BUG维护,

               功能不再新增。因此一般项目来说,使用1.x版本就可以了,

    2.x:不兼容ie678,很少有人使用,官方只做BUG维护,

               功能不再新增。如果不考虑兼容低版本的浏览器可以使用2.x,

    3.x:不兼容ie678,只支持最新的浏览器。除非特殊要求,

               一般不会使用3.x版本的,很多老的jQuery插件不支持这个版本。
  2. jquery-xxx.js 与 jquery-xxx.min.js区别:

    • jquery-xxx.js:开发版本。给程序员看的,有良好的缩进和注释。体积大一些

    • jquery-xxx.min.js:生产版本。程序中使用,没有缩进。体积小一些。程序加载更快

  3. js1.html,注意js文件src路径要书写正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div id="div1"> div1...</div>
</body>
<script>
//根据id 使用Jquery获取元素对象
var div1 = $("#div1");
alert(div1.html());
</script>
</html>

3.JQuery对象和JS对象区别与转换

  1. JQuery对象在操作时,更加方便。
  2. JQuery对象和js对象方法不通用的.
  3. 两者相互转换
    • jq – > js : jq对象[索引] 或者 jq对象.get(索引)
    • js – > jq : $(js对象)

4.选择器

  • 筛选具有相似特征的元素(标签)

  • 基本操作

    1. 事件绑定
           //1.获取b1按钮
           $("#b1").click(function(){
               alert("abc");
           });
    2. 入口函数

    ​ $(function () {

                });

    ​ window.onload 和 $(function) 区别

    ​ window.onload 只能定义一次,如果定义多次,后边的会将前边的覆盖掉。而后者是可以定义多次的。

    1. 样式控制:css方法
      // $(“#div1”).css(“background-color”,”red”);
      $(“#div1”).css(“backgroundColor”,”pink”);
  • 分类

    1. 基本选择器

      1. 标签选择器(元素选择器)

        • 语法: $(“html标签名”) 获得所有匹配标签名称的元素
      2. id选择器

        • 语法: $(“#id的属性值”) 获得与指定8id属性值匹配的元素
      3. 类选择器

        • 语法: $(“.class的属性值”) 获得与指定的class属性值匹配的元素
      4. 并集选择器:

        • 语法: $(“选择器1,选择器2….”) 获取多个选择器选中的所有元素
    2. 层级选择器

      1. 后代选择器
        • 语法: $(“A B “) 选择A元素内部的所有B元素
      2. 子选择器
        • 语法: $(“A > B”) 选择A元素内部的所有B子元素
    3. 属性选择器

      1. 属性名称选择器
        • 语法: $(“A[属性名]”) 包含指定属性的选择器
      2. 属性选择器
        • 语法: $(“A[属性名=’值’]”) 包含指定属性等于指定值的选择器
      3. 复合属性选择器
        • 语法: $(“A[属性名=’值’] []…”) 包含多个属性条件的选择器
    4. 过滤选择器

      1. 首元素选择器

        • 语法: $(:first ) 获得选择的元素中的第一个元素
      2. 尾元素选择器

        • 语法: $(:last) 获得选择的元素中的最后一个元素
      3. 非元素选择器

        • 语法: $(:not(selector) ) 不包括指定内容的元素

            例如选择class不为one的div:$(div:not(.one))
      4. 偶数选择器

        • 语法: $(:even) 偶数,从 0 开始计数
      5. 奇数选择器

        • 语法:$( :odd) 奇数,从 0 开始计数
      6. 等于索引选择器

        • 语法:$( :eq(index) ) 指定索引元素
      7. 大于索引选择器

        • 语法:$( :gt(index) ) 大于指定索引元素
      8. 小于索引选择器

        • 语法:$( :lt(index) ) 小于指定索引元素
      9. 标题选择器

        • 语法:$( :header) 获得标题(h1~h6)元素,固定写法
    5. 表单过滤选择器

      1. 可用元素选择器
        • 语法: :enabled 获得可用元素
      2. 不可用元素选择器
        • 语法: :disabled 获得不可用元素
      3. 选中选择器
        • 语法: :checked 获得单选/复选框选中的元素
      4. 选中选择器
        • 语法: :selected 获得下拉框选中的元素

5.DOM操作

  1. 内容操作

    1. html(): 获取/设置元素的标签体内容 <a><font>内容</font></a> –> <font>内容</font>
    2. text(): 获取/设置元素的标签体纯文本内容 <a><font>内容</font></a> –> 内容
    3. val(): 获取/设置元素的value属性值
  2. 属性操作

    1. 通用属性操作

           1. attr(): 获取/设置元素的属性
      1. removeAttr():删除属性
      2. prop():获取/设置元素的属性
      3. removeProp():删除属性
      • attr和prop区别?
          1. 如果操作的是元素的固有属性,则建议使用prop
              2. 如果操作的是元素自定义的属性,则建议使用attr
    2. 对class属性操作

      1. addClass():添加class属性值

      2. removeClass():删除class属性值

      3. toggleClass():切换class属性

        • toggleClass(“one”):

        • 判断如果元素对象上存在class=”one”,则将属性值one删除掉。 如果元素对象上不存在class=”one”,则添加

      4. css():

    3. CRUD操作:

      1. append():父元素将子元素追加到末尾
         * 对象1.append(对象2): 将对象2添加到对象1元素内部,并且在末尾
      2. prepend():父元素将子元素追加到开头
        • 对象1.prepend(对象2):将对象2添加到对象1元素内部,并且在开头
      3. appendTo():
        • 对象1.appendTo(对象2):将对象1添加到对象2内部,并且在末尾
      4. prependTo():
        • 对象1.prependTo(对象2):将对象1添加到对象2内部,并且在开头
      5. after():添加元素到元素后边
        • 对象1.after(对象2): 将对象2添加到对象1后边。对象1和对象2是兄弟关系
      6. before():添加元素到元素前边
        • 对象1.before(对象2): 将对象2添加到对象1前边。对象1和对象2是兄弟关系
      7. insertAfter()
        • 对象1.insertAfter(对象2):将对象1添加到对象2后边。对象1和对象2是兄弟关系
      8. insertBefore()
        • 对象1.insertBefore(对象2): 将对象1添加到对象2前边。对象1和对象2是兄弟关系
      9. remove():移除元素
        • 对象.remove():将对象删除掉
      10. empty():清空元素的所有后代元素。
        • 对象.empty():将对象的后代元素全部清空,但是保留当前对象以及其属性节点

6.动画:三种方式显示和隐藏元素

  1. 默认显示和隐藏方式

    1. show([speed,[easing],[fn]])
      1. speed:动画的速度。三个预定义的值(“slow”,”normal”, “fast”)或表示动画时长的毫秒数值(如:1000)
      2. easing:用来指定切换效果,默认是”swing”,可用参数”linear”
        • swing:动画执行时效果是 先慢,中间快,最后又慢
          • linear:动画执行时速度是匀速的
      3. fn:在动画完成时执行的函数,每个元素执行一次。
    2. hide([speed,[easing],[fn]])
    3. toggle([speed],[easing],[fn])
  2. 滑动显示和隐藏方式

         1. slideDown([speed],[easing],[fn])
    1. slideUp([speed,[easing],[fn]])
    2. slideToggle([speed],[easing],[fn])
  3. 淡入淡出显示和隐藏方式

    1. fadeIn([speed],[easing],[fn])
    2. fadeOut([speed],[easing],[fn])
    3. fadeToggle([speed,[easing],[fn]])

7.遍历

  1. js的遍历方式
    • for(初始化值;循环结束条件;步长)
  2. jq的遍历方式
    1. jq对象.each(callback)
       1. 语法:jquery对象.each(function(index,element){});
             * index:就是元素在集合中的索引
       * element:就是集合中的每一个元素对象
        * this:集合中的每一个元素对象
  3. 回调函数返回值:
    • true:如果当前function返回为false,则结束循环(break)。
    • false:如果当前function返回为true,则结束本次循环,继续下次循环(continue)
  4. $.each(object, [callback])
  5. for..of: jquery 3.0 版本之后提供的方式
    for(元素对象 of 容器对象)

8.事件绑定

  1. jquery标准的绑定方式

    • jq对象.事件方法(回调函数);
    • 注:如果调用事件方法,不传递回调函数,则会触发浏览器默认行为。
      • 表单对象.submit();//让表单提交
  2. on绑定事件/off解除绑定

     * jq对象.on("事件名称",回调函数)
    • jq对象.off(“事件名称”)
      • 如果off方法不传递任何参数,则将组件上的所有事件全部解绑
  3. 事件切换:toggle

     * jq对象.toggle(fn1,fn2...)
         * 当单击jq对象对应的组件后,会执行fn1.第二次点击会执行fn2.....
    
     * 注意:1.9版本 .toggle() 方法删除,jQuery Migrate(迁移)插件可以恢复此功能。
    
          <script src="../js/jquery-migrate-1.0.0.js" type="text/javascript" charset="utf-8"></script>

9.插件:增强Jquery的功能

  1. 实现方式:
    1. $.fn.extend(object)
       * 增强通过Jquery获取的对象的功能  $("#id")
    2. $.extend(object)
      • 增强JQeury对象自身的功能 $/jQuery

利用过滤器和动态代理过滤敏感词

需求

  • 当客户端中包含敏感词时,服务器端资源使用requst.getParameter获取参数值时,要先在过滤器中利用动态代理对象处理接收到的参数值后放行。
  • 例如:敏感词包括 笨蛋 蠢,服务器端有testServlet资源,当客户端输入http://localhost:8080/testServlet?msg=笨蛋吧 ,在服务器端中的过滤器中利用动态代理对象 将敏感次替换为***,然后进行后续处理

SensitiveWordFilter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@WebFilter("/*")
public class SensitiveWordFilter implements Filter {
public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//创建动态代理对象,增强getParameter方法
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter方法
//判断是否是getParameter方法
if (method.getName().equals("getParameter")){
//调用目标对象的getParameter,增强返回值
String res = (String) method.invoke(req, args);//将目标对象传递进去
if (res!=null){
//遍历敏感词列表
for (String str : list) {
if (res.contains(str)){
res = res.replaceAll(str, "***");
}
}
}
//返回增强后的值给request.getParameter(str)
return res;
}
return method.invoke(req, args);//当不执行getParameter方法时,仅执行method.invoke
}
});
//传递req的代理对象
chain.doFilter(proxy_req, resp);
}
//定义一个敏感词集合
private List<String> list = new ArrayList<String>();
public void init(FilterConfig config) throws ServletException {
try {
//获取文件的真实路径,加载文件
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词.txt");
//读取文件
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(realPath), "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//将每一行的数据添加到集合中
String line = null;
while ((line = bufferedReader.readLine())!=null){
list.add(line);
}
bufferedReader.close();
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}
}
}

testServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
@WebServlet("/testServlet")
public class testServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过Proxy_req对象调用getParameter方法,这里的request是Filter放行后的代理对象proxy_req
String msg = request.getParameter("msg");
System.out.println(msg);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}

代理模式Proxy

1.代理模式(Proxy)

  1. 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能

  2. 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象

  3. 代理模式有不同的形式,主要有三种:静态代理、动态代理(JDK代理、接口代理)、Cglib代理(可以在内存动态的创建对象,而不需要实现接口,属于动态代理范畴)

2.静态代理

  1. 基本介绍:

    静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。

  2. 静态代理优缺点

    优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展

    缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类

    ​ 一旦接口增加方法,目标对象与代理对象都要维护

  3. 应用实例

    • 具体要求

      1)定义一个接口:ITeacherDao

      2)目标对象TeacherDao实现接口 ITeacherDao

      3)使用静态代理方式,就需要在代理对象TeacherDaoProxy中也实现ITeacherDao

      4)调用的时候通过代理对象的方法来调用目标对象

      注意:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。

    • 类图

    • 具体代码

      ITeacherDao接口

      1
      2
      3
      public interface ITeacherDao {
      void teach();
      }

      TeacherDao 目标对象的类

      1
      2
      3
      4
      5
      6
      public class TeacherDao implements ITeacherDao{
      @Override
      public void teach() {
      System.out.println("授课中...");
      }
      }

      TeacherDaoProxy 代理对象类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public class TeacherDaoProxy implements ITeacherDao{
      //通过接口来聚合
      private ITeacherDao target;

      //构造器,参数应该传入ITeacherDao的实现类对象
      public TeacherDaoProxy(ITeacherDao target) {
      this.target = target;
      }

      @Override
      public void teach() {
      System.out.println("开始代理...");
      target.teach();//执行目标对象的teach方法java
      System.out.println("提交...");
      }
      }

      ProxyTest 测试类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      public class ProxyTest {
      public static void main(String[] args) {
      //创建目标对象(被代理对象)
      TeacherDao teacherDao = new TeacherDao();

      //创建代理对象,将目标对象(被代理对象)传递给代理对象
      ITeacherDao teacherDaoProxy = new TeacherDaoProxy(teacherDao);

      //通过代理对象,调用到被代理对象的方法
      //执行的是代理对象的方法,代理对象在去调用目标对象的方法
      teacherDaoProxy.teach();
      }
      }

3.动态代理

  1. 基本介绍

    • 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
    • 代理对象的生成:是利用JDK的API,动态的在内存中构建代理对象
    • 动态代理也叫:JDK代理、接口代理
  2. JDK中生成代理对象的API

    • 代理类所在包:import java.lang.reflect.Proxy;

    • JDK实现构建代理只需要使用Proxy.newProxyInstance方法,有三个参数

      ​ ClassLoader loader:指定当前目标对象使用的类加载器,真实对象.getClass().getClassLoader()
      ​ Class<?>[] interfaces:目标对象实现的接口类型,真实对象.getClass().getInterfaces()
      ​ InvocationHandler h:事件处理,执行代理对象方法时会触发事情处理器方法,new InvocationHander()

  3. 具体实例

    SaleComputer 接口

    1
    2
    3
    4
    public interface SaleComputer {
    public void show();
    public String sale(double money);
    }

    Lenovo 目标对象(被代理对象)类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Lenovo implements SaleComputer{

    @Override
    public void show() {
    System.out.println("展示电脑....");
    }

    @Override
    public String sale(double money) {
    System.out.println("花"+money+"买了电脑");
    return "联想电脑";
    }
    }

抽取一个ProxyFactory 类:获取动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public  class ProxyFactory <T>{
//目标对象 T泛指目标对象所实现的接口类型
private T target;
//在构造器中使用泛型 传递任意类型目标对象
public ProxyFactory(T target) {
this.target = target;
}

public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
/*代理逻辑编写的方法,代理对象调用所有方法都会触发该方法执行
* 参数:
* 1.proxy:代理对象
* 2.method:代理对象调用的方法,被封装为Method对象
* 3.args:代理对象调用方法时,传递的实际参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//
System.out.println("代理器执行了...");
//判断是否是sale方法
if(method.getName().equals("sale")){
//增强参数
double money = (double)args[0];
money = money * 0.85;
//使用真实对象调用该方法
String obj = (String) method.invoke(target, money);
System.out.println("代理器提交...");
//增强返回值类型
return obj+"_鼠标_鼠标垫";
}else{
Object res = method.invoke(target, args);//利用反射机制,使用method对象执行目标对象的方法
System.out.println("代理器提交...");
return res;
}
}
});
}
}

ProxyTest 测试类

1
2
3
4
5
6
7
8
9
10
11
12
public class ProxyTest {
public static void main(String[] args) {
//创建真实对象Lenovo
Lenovo lenovo = new Lenovo();
//创建ProxyFactory对象
SaleComputer proxyInstance = (SaleComputer) new ProxyFactory<SaleComputer>(lenovo).getProxyInstance();
//使用代理对象调用方法
proxyInstance.show();
String res = proxyInstance.sale(8000);
System.out.println(res);
}
}

执行结果

1
2
3
4
5
6
7
代理器执行了...
展示电脑....
代理器提交...
代理器执行了...
花6800.0买了电脑
联想电脑_鼠标_鼠标垫
代理器提交...

4.Cglib代理

  1. 基本介绍

    1)静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并 没有实现任何的接口,这个时候可以使用目标对象子类来实现代理——这就是Cglib代理

    2)Cglib代理也叫做子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展,有时候也将 Cglib代理归属到动态代理

    3)Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多 AOP的框架使用,例如Spring AOP,实现方法拦截

    4)在AOP编程中如何选择代理模式

    ​ 目标对象需要实现接口,用JDK代理

    ​ 目标对象不需要实现接口,用Cglib代理

    5)Cglib包的底层是通过使用**字节码处理框架(ASM)**来转换字节码并生成新的类

  2. Cglib代理模式实现步骤

    1)可以自己下载Cglib和asm的jar包,

    ​ 下载链接:https://mvnrepository.com/artifact/cglib/cglib/3.3.0

    https://mvnrepository.com/artifact/org.ow2.asm

    ​ 所需要下载的jar包:asm.jar asm-commons.jar asm-tree.jar cglib.jar

    也可以使用Spring-core.jar中的org.springframework.cglib

    2)在内存中动态构建子类,注意代理的类不能为final,否则报错java.lang.IllegalArgumentException;

    3)目标对象的方法如果是final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。

  3. 具体实例

TeacherDao:被代理对象

1
2
3
4
5
public class TeacherDao {
void teach(){
System.out.println("授课中....");
}
}

ProxyFactory:用来获取代理对象,其中getProxyFactory()给目标对象targe创建一个代理对象。intecept是实现MethodInterceptor接口中的方法,实现对被代理对象方法的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class ProxyFactory implements MethodInterceptor {

//维护一个目标对象
private Object target;
//传入被代理对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个target的代理对象
public Object getProxyInstance(){
//创建一个工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类即代理对象
return enhancer.create();
}
//重写intercept方法,会调用目标对象的方法
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理模式开始");
Object val = method.invoke(target, args);
System.out.println("Cglib代理提交");
return val;
}
}

client:

1
2
3
4
5
6
7
8
9
10
11
public class Client {
public static void main(String[] args) {
//创建目标对象
TeacherDao teacherDao = new TeacherDao();
//创建ProxyFactory,传递目标对象,并获取代理对象
TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(teacherDao).getProxyInstance();

//执行代理对象的方法,触发intercept方法,实现对目标对象的注入
proxyInstance.teach();
}
}

5. Proxy代理模式的变体

几种常见的代理模式介绍

1)防火墙代理

​ 内网通过代理穿透防火墙,实现对公网的访问

2)缓存代理

​ 比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则OK,如果取不到资源,再到公网或者数据库取,然后缓存。

3)远程代理

​ 远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。

4)同步代理

​ 主要使用再多线程编程中,完成多线程间同步工作

Fileter过滤器

1. 基本定义

  1. 过滤器的作用
    • 一般用于完成通用操作。如登陆验证、同意编码处理、敏感字符过滤
  2. 快速入门
    • 定义一个类,实现接口Filter,包为javax.servlet
    • 复写方法doFilter
    • 配置拦截路径:配置web.xml或注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebFilter("/*")//注解配置,访问所有资源之前,都会执行该过滤器
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器。。。。");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
}

2. 过滤器细节

2.1 web.xml配置

  • 在web.xml中的web-app标签体内加入下面代码
1
2
3
4
5
6
7
8
9
<filter>
<filter-name>demo1</filter-name>
<filter-class>cn.hxx.web.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<!--拦截路径-->
<url-pattern>/*</url-pattern>
</filter-mapping>
  • WebFilter注解源码:@webFilter用于将注解过滤器,该注解在部署时被容器处理,容器根据具体的属性将相应的类部署为过滤器。该注解有以下属性,均有默认值。但是value、urlPatterns、servletNames三者至少包含一个,且value和urlPatterns一般不要同时赋值,如果同时指定,通常忽略value的取值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {
String description() default "";//该过滤器的描述信息,等价与<description>标签

String displayName() default "";//该过滤器的显示名,通常配合工具使用,等价与<displayName>标签

WebInitParam[] initParams() default {};//指定一组过滤器初始化参数,等价于<init-param>

String filterName() default "";//指定过滤器的name属性,等价于<filter-name>属性

String smallIcon() default "";

String largeIcon() default "";

String[] servletNames() default {};//指定过滤器将应用于哪些servlet。取值是@WebServlet中的name属性的取值,或者是web.xml中<servlet-name>的取值

String[] value() default {};//等价于urlPatterns

String[] urlPatterns() default {};//指定一组过滤器的URL匹配模式,等价于<url-pattern>标签

DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};//指定过滤器的转发模式,包括:ASYNC、ERROR、FORWORD、INCLUDE、REQUEST

boolean asyncSupported() default false;//声明过滤器是否支持异步操作模式,等价于<async-support>标签
}

2.2过滤器执行流程

客户端请求A资源,先执行过滤器放行之前的代码,过滤器放行后执行A资源,然后执行放行代码下的程序

  1. 执行过滤器

  2. 执行放行后的资源

  3. 执行过滤器放行代码下的代码

2.3过滤器生命周期方法

  1. init方法:服务器启动后,会创建Filter对象,然后调用init方法。用于加载资源

  2. dofilter方法:每一次请求被拦截资源时,会执行该方法

  3. destroy方法:服务器正常关闭,Filter对象被销毁,会执行destroy方法。用于释放资源

2.4过滤器配置详解

  1. 拦截路径的配置

    • 配置1:具体的资源路径:/index.jsp 或 /findServlet 只有访问该资源时,过滤器才会被执行

    • 配置2:目录拦截:/user/* 访问/user下的所有资源时,过滤器都会被执行

      1
      2
      3
      4
      5
      @WebServlet("/user/CheckCodeServlet")
      @WebServlet("/user/failServlet")
      //在web目录下还可以建立user子目录,里面也可以存放资源
      @WebFilter("/user/*")
      //访问servlet和访问user目录下的资源都会执行该过滤器
    • 配置3:后缀名拦截:*.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行

    • 配置4:/* 拦截所有资源

  2. 拦截方式的配置:资源被访问的方式

    • 配置1:注解配置dispatcherTypes,数组,可配置多个选项

      (1) REQUEST:默认值,浏览器直接请求资源

      (2) FORWARD:转发访问资源

      (3) INCLUDE:包含访问资源

      (4) ERROR:错误跳转资源

      (5) ASYNC:异步访问资源

      1
      2
      @WebFilter(value = "/index.jsp",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})java
      //转发到index.jsp 和 直接访问index.jsp 都会执行该过滤器

2.5过滤器链(配置多个过滤器)

  • 执行顺序:有两个过滤器:过滤器1、过滤器2

    1. 过滤器1
    2. 过滤器2
    3. 资源
    4. 过滤器2
    5. 过滤器1
  • 过滤器先后顺序

    1. 注解配置:按照类名的字符串比较规则比较,值小的先执行

      如:AFilter 和 BFilter

    2. web.xml配置:filter-mapping谁定义在上面,谁先执行

三层架构

三层架构:软件设计架构

  1. 界面层(表示层/web层):用户看到的界面,用户可以通过界面上的组件和服务器进行交互
    • 控制器:servlet,接收用户的请求,获取用户提交的参数信息,将数据封装,然后调用业务逻辑层、数据访问层,将得到的数据转发到sp页面,给客户端做出响应。
    • 包的命名:cn.项目名.web
    • 对应框架:SpringMVC框架
  2. 业务逻辑层(service层):处理业务逻辑。组合Dao层中的简单方法,形成复杂的功能(业务逻辑操作)
    • 包的命名:cn.项目名.service
    • 对应框架:Spring框架
  3. 数据访问层(Dao层):操作数据存储文件,Data Access Object。定义了对数据库最基本的CRUD操作
    • 包的命名:cn.项目名.Dao
    • 对应框架:MyBatis框架

JSTL标签库

1.概念

  1. JavaServer Pages Tag Library (JSP标准标签库)
  2. 用于简化和替换jsp页面上的Java代码
  3. 使用

2.常用的JSTL标签

  1. if:相当于Java代码的if

    • test属性:必须属性 接收Boolean表达式,如果表达式为true则显示if标签体内容,为false则不显示。一般情况下,test属性值会和EL表达式一起使用
  2. choose:相当于switch

    • 案例:完成数字编号对应星期几案例

    ​ 1.域中存储一数字
    ​ 2.使用choose标签取出数字 ,相当于switch
    ​ 3.使用when标签做数字判断,相当于case
    ​ 4.otherwise标签做其他情况的声明,相当于default

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <%
    request.setAttribute("day",54);
    %>
    <c:choose>
    <c:when test="${day==1}">星期一</c:when>
    <c:when test="${day==2}">星期二</c:when>
    <c:when test="${day==3}">星期三</c:when>
    <c:when test="${day==4}">星期四</c:when>
    <c:when test="${day==5}">星期五</c:when>
    <c:when test="${day==6}">星期六</c:when>
    <c:when test="${day==7}">星期七</c:when>
    <c:otherwise>输入有误</c:otherwise>
    </c:choose>
  3. foreach:相当于for

    • 完成重复操作

    ​ begin:开始值
    ​ end:结束值
    ​ var:临时变量
    ​ step:步长
    ​ varStatus:循环状态对象
    ​ index:容器中元素索引,从0开始
    ​ count:循环次数,从1开始

    • 遍历容器

    ​ items:容器对象
    ​ var:容器中元素的临时变量
    ​ varStatus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<c:forEach begin="1" end="10" step="2" var="i" varStatus="s">
${i}
<h3>${s.index}</h3>
<h4>${s.count}</h4>
</c:forEach>

<hr>

<%
List list = new ArrayList();
list.add("hxx");
list.add("qzy");
request.setAttribute("list",list);
%>
<c:forEach items="${requestScope.list}" var="str" varStatus="s">
${str}
<h3>${s.index}</h3>
<h4>${s.count}</h4>
</c:forEach>

3.案例

将用户信息全部显示在表格中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<%
List list = new ArrayList();
list.add(new User("hxx",new Date()));
list.add(new User("qzy",new Date()));
request.setAttribute("list",list);
%>
<table border="1" width="500px" align="center">
<tr>
<td>编号</td>
<td>姓名</td>
<td>生日</td>
</tr>
<%--数据行--%>
<c:forEach items="${list}" var="user" varStatus="s">
<tr>
<td>${s.count}</td>
<td>${user.name}</td>
<td>${user.birStr}</td>
</tr>
</c:forEach>
</table>
</body>