之所以把这三个放在一起说是因为这些东西的内容都比较少。优势JAVA-web的一些收尾部分,所以放在最后一起进行一个复习。
作用:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
应用: 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
它的学习过程和servlet是一致的,
第一步是学习如何创建,即继承一个接口,然后重写其中的方法。
第二步是学习其中的三种生命周期方法,用的比较多的就是doFilter。
第三步就是学习如何配置滤波器,配置滤波器还是有两种方法,一个是xml配置,一个是注解配置,主要掌握后者的配置方法。
接下来就是两个案例:
这里是直接在前一天的大作业的基础上完成的,比较简单,首先我们先将filter上面的配置设置为对所有资源都进行过滤,随后需要设置对一些用于登录的资源直接进行放行,这些用于登录的资源包括:
package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/*")
public class LoginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String uri = request.getRequestURI();
if(uri.contains("/login.jsp") || uri.contains("loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/") || uri.contains("/checkCodeServlet")){
chain.doFilter(req,resp);
}else{
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
if(user != null){
chain.doFilter(req,resp);
}else{
request.setAttribute("login_msg","您尚未登录,请您先登录");
request.getRequestDispatcher("login.jsp").forward(request,resp);
}
}
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
这里的增强就这涉及一种设计模式了,即代理设计模式,这种设计模式就是用来对对象的方法进行增强的,需要掌握下面一些基础知识:
下面举一个卖电脑的例子:
就相当于我们要买电脑的话直接找西安的代理商买就行了,西安的代理商可能会给你一定程度上的优惠,这个优惠就相当于对参数列表进行了增强。
首先真实对象和代理对象都需要实现一个共同的接口,在这里我们定义一个卖电脑的接口,其中有两个方法,一个是sale(),一个是show()。
package cn.itcast.proxy;
public interface SaleComputer {
public String sale(double money);
public void show();
}
接着我们创建一个联想类来实现这个接口:
package cn.itcast.proxy;
/**
* 真实类
*/
public class Lenovo implements SaleComputer {
@Override
public String sale(double money) {
System.out.println("花了"+money+"元买了一台联想电脑...");
return "联想电脑";
}
@Override
public void show() {
System.out.println("展示电脑....");
}
}
随后我们创建一个用于代理设计模式的测试类,这些都是一些固定写法:
package cn.itcast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest2 {
public static void main(String[] args) {
Lenovo lenovo = new Lenovo();
/*
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
@Override
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return null;
}
});
}
}
这就是基本的一个框架,invoke函数就用于写增强对象的一些手段:
比如我们对售卖的这个方法进行增强,打折并送鼠标垫,而且送货上门。
所以我们在invoke中如下:
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if(method.getName().equals("sale")){
double money =(double)objects[0]*0.8;
System.out.println("专车接你");
Object invoke = method.invoke(lenovo, money);
System.out.println("送货上门");
return invoke+"+鼠标垫";
}else{
Object obj = method.invoke(lenovo);
return null;
}
}
这样就实现了对对象的一种增强。
同样,针对我们的敏感词过滤,主要是在getParameter()的返回值上做文章。
我们需要在init()函数中将敏感词给读入并存在集合中,具体操作如下:
public void init(FilterConfig config) throws ServletException {
String path = config.getServletContext().getRealPath("/WEB-INF/classes/敏感词汇.txt");
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line = null;
while ((line = br.readLine())!=null){
list.add(line);
}
br.close();
System.out.println(list);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
然后再在我们的doFilter函数中进行增强的逻辑,然后放行:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if(method.getName().equals("getParameter")){
String value = (String)method.invoke(req, objects);
if(value != null){
for (String s : list) {
if(value.contains(s)){
value.replaceAll(s,"xxx");
}
}
}
return value;
}
return method.invoke(req,objects);
}
});
chain.doFilter(req, resp);
}
这样就实现了敏感词的过滤。
首先还是介绍一下概念:
一个JavaScript框架。简化JS开发
* jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨 是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优 化HTML文档操作、事件处理、动画设计和Ajax交互。
接着就有:
<html>
<head>
<meta charset="UTF-8">
<title>jquery案例之抽奖title>
<script type="text/javascript" src="../js/jquery-3.3.1.min.js">script>
<script language='javascript' type='text/javascript'>
/*
分析:
1. 给开始按钮绑定单击事件
1.1 定义循环定时器
1.2 切换小相框的src属性
* 定义数组,存放图片资源路径
* 生成随机数。数组索引
2. 给结束按钮绑定单击事件
1.1 停止定时器
1.2 给大相框设置src属性
*/
var imgs = ["../img/man00.jpg",
"../img/man01.jpg",
"../img/man02.jpg",
"../img/man03.jpg",
"../img/man04.jpg",
"../img/man05.jpg",
"../img/man06.jpg",
];
var startId;
var index;
$(function () {
$("#startID").prop("disabled",false);
$("#stopID").prop("disables",true);
$("#startID").click(function () {
$("#startID").prop("disabled",true);
$("#stopID").prop("disables",false);
startId = setInterval(function () {
index = Math.floor(Math.random()*7);
$("#img1ID").prop("src",imgs[index]);
},20);
});
$("#stopID").click(function () {
$("#startID").prop("disabled",false);
$("#stopID").prop("disables",true);
clearInterval(startId);
$("#img2ID").prop("src",imgs[index]).hide();
$("#img2ID").show(1000);
})
});
script>
head>
<body>
<div style="border-style:dotted;width:160px;height:100px">
<img id="img1ID" src="../img/man00.jpg" style="width:160px;height:100px"/>
div>
<div
style="border-style:double;width:800px;height:500px;position:absolute;left:500px;top:10px">
<img id="img2ID" src="../img/man00.jpg" width="800px" height="500px"/>
div>
<input
id="startID"
type="button"
value="点击开始"
style="width:150px;height:150px;font-size:22px">
<input
id="stopID"
type="button"
value="点击停止"
style="width:150px;height:150px;font-size:22px">
body>
html>
其实在redis之前还有一个关于ajax和json的学习,但是感觉没什么好说的,主要说一下这两个工具的作用吧。
ajax:
ASynchronous JavaScript And XML 异步的JavaScript 和 XML
1. 异步和同步:客户端和服务器端相互通信的基础上
* 客户端必须等待服务器端的响应。在等待的期间客户端不能做其他操作。
* 客户端不需要等待服务器端的响应。在服务器处理请求的过程中,客户端可以进行其他的操作。
2.Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
提升用户的体验。
json:
以一个案例来将这两个技术来进行结合:
这里就是在我们的注册界面,当我们输入用户名的时候,设置一个离焦的事件,一旦离焦,就触发我们的后台验证机制,检查数据库中是否存在这样的用户名,如果存在,就提示客户换一个用户名,不存在则提示用户名可用。这里为了精简程序就没有写后台数据库的程序,直接在servlet上进行一个判断,验证输入的用户名是否存在。
其中用到了jackson用来解析json,将java类转化为json。
html代码:
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="js/jquery-3.3.1.min.js">script>
<title>案例title>
<script>
//在页面加载完成后
$(function () {
$("#username").blur(function () {
var username = $(this).val();
$.get("findUserServlet",{
username:username},function (data) {
var span = $("#s_username");
if(data.userExsit){
span.css("color","red")
span.html(data.msg);
}else{
span.css("color","green")
span.html(data.msg);
}
})
})
});
script>
head>
<body>
<form>
<input type="text" id="username" name="username" placeholder="请输入用户名">
<span id="s_username">span>
<br>
<input type="password" name="password" placeholder="请输入密码"><br>
<input type="submit" value="注册"><br>
form>
body>
html>
FindUserServlet
package cn.itcast.web.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/findUserServlet")
public class FindUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json;charset=utf-8");
String username = request.getParameter("username");
Map<String, Object> map = new HashMap<>();
if("tom".equals(username)){
map.put("userExsit",true);
map.put("msg","用户名重复,请重新输入");
}else {
map.put("userExist",false);
map.put("msg","用户名可用");
}
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getWriter(),map);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
终于到redis了
有关redis就提一点,那就是使用连接池的一个工具类,可以直接获取连接池对象,这里和前面的JDBC工具类几乎是一样的:
package utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class JedisUtils {
private static JedisPool jedisPool;
//获取文件的配置
static {
InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
Properties pro = new Properties();
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
}
//获取连接的方法
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
还是直接用一个例子来结束java_web的复习吧,做一个省份下拉框,可以从数据库中查询到服务器希望用户看到的省份名称。但每次都需要从数据库中查未免太麻烦了,所以可以第一次先写到redis中,以后每次都从redis中获取数据就方便多了。
这里后面的dao中就不写了,主要就写sevlet和service中的程序以及前端数据获取和展示的程序。
首先是前端:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="js/jquery-3.3.1.min.js">script>
<script>
$(function () {
//发送ajax请求,加载所有省份数据
$.get("provinceServlet",{
},function (data) {
//[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"广州"},{"id":4,"name":"陕西"}]
//1.获取select
var province = $("#province");
//2.遍历json数组
$(data).each(function () {
//3.创建
var option = "+this.name+"";
//4.调用select的append追加option
province.append(option);
});
});
});
script>
head>
<body>
<select id="province">
<option>
--请选择省份--
option>
select>
body>
html>
其主要代码就是对获取的json数据进行遍历,并将其创建为option标签,再一一添加进province的下拉表单中。
接着就是ProvinceServlet,这里我们直接将后台service业务层传来的json字符串给输出到前端就可以了。
package cn.itcast.servlet;
import cn.itcast.domain.Province;
import cn.itcast.service.UserService;
import cn.itcast.service.serviceImp.UserServiceImp;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/provinceServlet")
public class ProvinceServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.调用service查询
UserService service = new UserServiceImp();
String json = service.findAllJson();
System.out.println(json);
//3.响应结果
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
接着就是最重要的serviceImpl了,这里的逻辑是,直接去获取redis中的内容,如果不存在province这一个内容,那么我们就去数据库中查找给添加回去,并返回给servlet,如果存在直接给返回。
package cn.itcast.service.serviceImp;
import cn.itcast.dao.UserDao;
import cn.itcast.dao.daoImp.UserDaoImp;
import cn.itcast.domain.Province;
import cn.itcast.jedis.util.JedisUtils;
import cn.itcast.service.UserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;
import java.util.List;
public class UserServiceImp implements UserService {
private UserDao dao = new UserDaoImp();
@Override
public List<Province> findAll() {
return dao.findAll();
}
@Override
public String findAllJson() {
//1.先从redis中查询数据
//1.1获取redis客户端连接
Jedis jedis = JedisUtils.getJedis();
String province_json = jedis.get("province");
//2判断 province_json 数据是否为null
if(province_json == null || province_json.length() == 0){
//redis中没有数据
System.out.println("redis中没数据,查询数据库...");
//2.1从数据中查询
List<Province> ps = dao.findAll();
//2.2将list序列化为json
ObjectMapper mapper = new ObjectMapper();
try {
province_json = mapper.writeValueAsString(ps);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
//2.3 将json数据存入redis
jedis.set("province",province_json);
//归还连接
jedis.close();
}else{
System.out.println("redis中有数据,查询缓存...");
}
return province_json;
}
}
注意:做这个案例的时候一定要把redis服务器给打开,否则都是白搭,我当时就是试了半天,前端一直显示不出省份,最后把服务器打开就可以了。