复习5:filter、JQuery、redis

之所以把这三个放在一起说是因为这些东西的内容都比较少。优势JAVA-web的一些收尾部分,所以放在最后一起进行一个复习。

1.过滤器filter

作用:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
应用: 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
它的学习过程和servlet是一致的,
第一步是学习如何创建,即继承一个接口,然后重写其中的方法。
第二步是学习其中的三种生命周期方法,用的比较多的就是doFilter。
第三步就是学习如何配置滤波器,配置滤波器还是有两种方法,一个是xml配置,一个是注解配置,主要掌握后者的配置方法。
在这里插入图片描述

  • 拦截路径配置:
    1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
    2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
    3. 后缀名拦截: .jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
    4. 拦截所有资源:/
    访问所有资源时,过滤器都会被执行
    * 拦截方式配置:资源被访问的方式
    * 注解配置:
    * 设置dispatcherTypes属性
    1. REQUEST:默认值。浏览器直接请求资源
    2. FORWARD:转发访问资源
    3. INCLUDE:包含访问资源
    4. ERROR:错误跳转资源
    5. ASYNC:异步访问资源

接下来就是两个案例:

1. 登录的检测,只有在登录之后才能进行操作,不能像原先那样直接通过网址对内部资源进行访问。

这里是直接在前一天的大作业的基础上完成的,比较简单,首先我们先将filter上面的配置设置为对所有资源都进行过滤,随后需要设置对一些用于登录的资源直接进行放行,这些用于登录的资源包括:

  • loginServlet
  • login.jsp
  • checkCodeServlet
    不要忘了,为了保留原先的样式和一些动态的效果,还需要把我们导入的bootstrap中的一些资源文件进行放行:
  • css
  • js
  • font
    我们前面为了设置一个欢迎的功能,在session中存入了user,所以这里我们直接通过session把user给获取出来,如果是存在的,那么我们就直接放行,如果不存在就需要我们对前端转发一些登录错误信息了。
    最后的代码如下所示:
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() {
     

    }
}

2.敏感字符的检测,将敏感字符进行和谐

其大致的思路如下:
复习5:filter、JQuery、redis_第1张图片

这里的增强就这涉及一种设计模式了,即代理设计模式,这种设计模式就是用来对对象的方法进行增强的,需要掌握下面一些基础知识:
复习5:filter、JQuery、redis_第2张图片
下面举一个卖电脑的例子:
复习5:filter、JQuery、redis_第3张图片
就相当于我们要买电脑的话直接找西安的代理商买就行了,西安的代理商可能会给你一定程度上的优惠,这个优惠就相当于对参数列表进行了增强。
首先真实对象和代理对象都需要实现一个共同的接口,在这里我们定义一个卖电脑的接口,其中有两个方法,一个是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);
    }

这样就实现了敏感词的过滤。

2.Jquery

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

接着就有:

  1. JQ对象和JS对象的转换
  2. jq – > js : jq对象[索引] 或者 jq对象.get(索引)
    js – > jq : $(js对象)
  3. 五种选择器
    1)基本选择器
    就是基本的根据id、标签、class来进行选择
    2)层级选择器
    只有两种:后代选择器和子选择器
    3)属性选择器
    能够选择包含某一属性的标签,以及属性特定的标签
    4)过滤选择器
    比如选择第一个div标签或者偶数个类似的这种选择器
    5)表单选择器
    对表单中的一些属性进行判断
  4. DOM操作
    1)内容操作
    2)属性操作
  1. CRUD
    接着就是这一章的一些案例,比较简单,就不列举了,随后就是JQ的提升部分:
  1. 动画
  2. 遍历
    复习5:filter、JQuery、redis_第4张图片
  3. 事件绑定
    最后以一个案例作为结束,就是抽图片,左边图片随机滚动,摁下停止按钮之后,将当前滚到的图片显示到屏幕的右侧。
    首先我们需要设置按键的状态,设置初始状态为开始可点,停止不可点。随后我们需要对按键的逻辑进行判断,点击开始按钮,那么就会设置开始不可点,停止可点。接着就是设置一个定时器,让每二十秒重复随机生成一个数,然后将这个数作为索引用于我们提前就生成的数组中,然后为src属性赋值。停止按钮更加简单,点击之后依然是设置状态,然后就是停止计数,将当前的img[index]赋给右边框的src属性。这里需要注意的一点是,需要提前设置两个变量,一个是index,一个是startID,这都是停止中需要直接进行操作了,所以需要在scrip层的第一层进行设置。

<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>

3.redis

其实在redis之前还有一个关于ajax和json的学习,但是感觉没什么好说的,主要说一下这两个工具的作用吧。
ajax:
ASynchronous JavaScript And XML 异步的JavaScript 和 XML
1. 异步和同步:客户端和服务器端相互通信的基础上
* 客户端必须等待服务器端的响应。在等待的期间客户端不能做其他操作。
* 客户端不需要等待服务器端的响应。在服务器处理请求的过程中,客户端可以进行其他的操作。
复习5:filter、JQuery、redis_第5张图片
2.Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
提升用户的体验。
json:

  • json现在多用于存储和交换文本信息的语法
  • 进行数据的传输
  • JSON 比 XML 更小、更快,更易解析。

以一个案例来将这两个技术来进行结合:
这里就是在我们的注册界面,当我们输入用户名的时候,设置一个离焦的事件,一旦离焦,就触发我们的后台验证机制,检查数据库中是否存在这样的用户名,如果存在,就提示客户换一个用户名,不存在则提示用户名可用。这里为了精简程序就没有写后台数据库的程序,直接在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服务器给打开,否则都是白搭,我当时就是试了半天,前端一直显示不出省份,最后把服务器打开就可以了。

你可能感兴趣的:(JAVA学习)