WEB由浅入深-04篇

168 阅读5分钟

学习插图.jpg

前篇

过滤器Filter

  • Filter也属于Servlet规范
  • Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
  • 配置Filter,可以用注解@WebFilter,也可以使用xml文件 filter、filter-mapping
  • Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter("*.do")表示拦截所有以.do结尾的请求
  • 过滤器链:
    • 如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
    • 如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
  • Filter执行的流程:请求过来之后,先进行过滤,然后进行放行,当返回数据时,又会进行过滤,然后再返回给浏览器。
  • 编码举例:
@WebServlet("/demo01.do")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo01...service..");
        req.getRequestDispatcher("succ.html").forward(req,resp);
    }
}

没有Filter的执行情况:

2023-02-07_120636.jpg 添加Filter:

/**
 * @author crystal
 * @create 2023-02-07 11:15
 */
@WebFilter("/demo01.do")
public class Demo01Filter 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("filter ...");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("after filter...");
    }

    @Override
    public void destroy() {

    }
}

2023-02-07_120850.jpg 过滤器链编码举例:

@WebServlet("/demo02.do")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo02...service..");
        req.getRequestDispatcher("succ.html").forward(req,resp);
    }
}
@WebFilter("*.do")
public class Filter01 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("A");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("A2");
    }

    @Override
    public void destroy() {

    }
}
@WebFilter("*.do")
public class Filter02 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("B");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("B2");
    }

    @Override
    public void destroy() {

    }
}
@WebFilter("*.do")
public class Filter03 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("C");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("C2");
    }

    @Override
    public void destroy() {

    }
}

过滤器链的执行顺序(具体说明看第一段): 2023-02-07_121125.jpg

Filter的应用:

  • 在请求到达DispatcherServlet、或者Controller层的时候,提前使用Filter设置编码,然后放行请求。
  • 注解方式也可以替代成XML的方式
@WebFilter(urlPatterns ={"*.do"} ,initParams = {@WebInitParam(name = "ecoding",value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {

    private String encoding = "UTF-8";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String encodingStr = filterConfig.getInitParameter("encoding");
        if (StringUtil.isNotEmpty(encodingStr)){
            encoding = encodingStr;
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ((HttpServletRequest)servletRequest).setCharacterEncoding("UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

编程式事务管理应用

public class ConnUtil {
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    public static Connection createConn(){
        try {
            InputStream inputStream = ConnUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(inputStream);
            String driverClass = pros.getProperty("driverClass");
            Class.forName(driverClass);
            String url = pros.getProperty("url");
            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            Connection connection = DriverManager.getConnection(url, user, password);
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Connection getConn() throws SQLException {
        Connection conn = threadLocal.get();
        if (conn == null){
            conn = createConn();
            threadLocal.set(conn);
        }
        return threadLocal.get();
    }

    public static void close() throws SQLException {
        Connection conn = threadLocal.get();
        if (conn == null){
            return;
        }
        if (!conn.isClosed()){
            conn.close();
            threadLocal.set(null);
        }
    }
}
public class TransactionManager {

//开启事务
    public static void beginTrans() throws SQLException {
        ConnUtil.getConn().setAutoCommit(false);
    }
//提交事务
    public static void commit() throws SQLException {
        Connection conn = ConnUtil.getConn();
        conn.commit();
        conn.close();
    }

//回滚事务
    public static void rollback() throws SQLException {
        Connection conn = ConnUtil.getConn();
        conn.rollback();
        conn.close();
    }
}
@WebFilter("*.do")
public class openSessionInViewFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
//            开启事务
            TransactionManager.beginTrans();
            filterChain.doFilter(servletRequest,servletResponse);
//            提交事务
            TransactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            try {
//                回滚事务
                TransactionManager.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public void destroy() {

    }
}
package com.crystal.myssm;

import com.crystal.exceptions.BaseDAOException;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author crystal
 * @create 2023-01-15 13:24
 */
public class BaseDAO<E> {
//    获取连接
    public Connection getConn() throws SQLException {
      return  ConnUtil.getConn();
    }
//    关闭连接
    public void closeRes(Connection conn, PreparedStatement ps, ResultSet rs){

    }
    private Class clazz;
    public BaseDAO(){
        Type genericSuperclass = getClass().getGenericSuperclass();
        Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
        Type argument = actualTypeArguments[0];
        try {
            clazz = Class.forName(argument.getTypeName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

//    获取所有的列表信息
    public <E> List<E> getList(String sql,Object...args){
        List list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = getConn();
             ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1,args[i]);
            }
             rs = ps.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            while(rs.next()){
                E e = (E) clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    Field field = e.getClass().getDeclaredField(columnLabel);
                    Object objectVal = rs.getObject(i + 1);
                    field.setAccessible(true);
                    field.set(e,objectVal);
                }
                list.add(e);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseDAOException("BaseaDAO出错了。。。");
        }
    }

//    获取单个的信息
    public <E> E getOne(String sql,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = getConn();
             ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1,args[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            if (rs.next()){
                E e = (E) clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    Object objectVal = rs.getObject(i + 1);
                    Field field = e.getClass().getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(e,objectVal);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseDAOException("BaseaDAO出错了。。。");
        }
        return null;
    }

//   修改单个信息
    public int updateOne(String sql,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        try {
             conn = getConn();
             ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1,args[i]);
            }
            int val = ps.executeUpdate();
            return val;
        }catch (Exception e){
            e.printStackTrace();
            throw new BaseDAOException("BaseaDAO出错了。。。");
        }
    }

//    查询特殊值
    public <E> E getValue(String sql,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1,args[i]);
            }
            rs = ps.executeQuery();
            if (rs.next()){
                Object objectVal = rs.getObject(1);
                return (E) objectVal;
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new BaseDAOException("BaseaDAO出错了。。。");
        }
        return null;
    }
}
package com.crystal.myssm;

import com.crystal.exceptions.BaseDAOException;
import com.crystal.exceptions.DispatcherServletException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author crystal
 * @create 2023-02-05 15:16
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

    Map<String,Object> beanMap = new HashMap<>();

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
//        读取配置文件,将实例装进map集合
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(inputStream);
            NodeList beanNodeList = document.getElementsByTagName("bean");
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
                    String id = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class<?> clazz = Class.forName(className);
                    Object classObj = clazz.newInstance();
                    beanMap.put(id,classObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new DispatcherServletException("DispatcherServlet出错了。。。");
        }
    }


    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController

        Object beanObj = beanMap.get(servletPath);

//        获取前端的参数operate
        String operate = request.getParameter("operate");
        if (operate == null){
            operate = "index";
        }

//        根据反射调用方法
        try {
//           获取方法的参数列表
            Method[] methods = beanObj.getClass().getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                if (operate.equals(method.getName())){
                    Parameter[] parameters = method.getParameters();
                    Object[] parameterVals = new Object[parameters.length];
                    for (int j = 0; j < parameters.length; j++) {
                        Parameter parameter = parameters[j];
                        String parameterName = parameter.getName();
                        if ("request".equals(parameterName)){
                            parameterVals[j] = "request";
                        }else if ("response".equals(parameterName)){
                            parameterVals[j] = "response";
                        }else if ("session".equals(parameterName)){
                            parameterVals[j] = request.getSession();
                        }else{
                            String parameterval = request.getParameter(parameterName);
                            parameterVals[j] = parameterval;
                            Class<?> parameterType = parameter.getType();
                            Object parameterObj = parameterVals[j];
                            if (parameterObj != null){
                                if ("java.lang.Integer".equals(parameterType)){
                                    parameterObj = Integer.parseInt(parameterval);
                                }
                                parameterVals[j] = parameterObj;
                            }
                        }
                    }
             if (method != null){
//                调用controller中对应的方法
                method.setAccessible(true);
                Object ObjStr = method.invoke(beanObj,parameterVals);

//                视图处理
                String returnStr = (String) ObjStr;
                if (returnStr.startsWith("redirect:")){
                    String redirectVal = returnStr.substring("redirect:".length());
                    response.sendRedirect(redirectVal);
                }else{
                    super.processTemplate(returnStr,request,response);
                }
            }else{
                throw new RuntimeException("operate的值非法!");
            }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new DispatcherServletException("DispatcherServlet出错了。。。");
        }
    }
}

ThreadLocal

  • get() , set(obj)
  • ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据
  • set方法源码分析:
public void set(T value) {
         Thread t = Thread.currentThread(); //获取当前的线程
         ThreadLocalMap map = getMap(t);    //每一个线程都维护各自的一个容器(ThreadLocalMap)
         if (map != null)
             map.set(this, value);          //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)
         else
             createMap(t, value);           //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化
     } 
  • get方法源码分析:
public T get() {
         Thread t = Thread.currentThread(); //获取当前的线程
         ThreadLocalMap map = getMap(t);    //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)
         if (map != null) {
             ThreadLocalMap.Entry e = map.getEntry(this);   //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带
             if (e != null) {
                 @SuppressWarnings("unchecked")
                 T result = (T)e.value;     //entry.value就可以获取到工具箱了
                 return result;
             }
         }
         return setInitialValue();
     }

监听器

1) ServletContextListener - 监听ServletContext对象的创建和销毁的过程
2) HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
3) ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程

4) ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
5) HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
6) ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)

7) HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
8) HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化

ServletContextListener的应用 - ContextLoaderListener

@WebListener
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext();
        ServletContext application = servletContextEvent.getServletContext();
        application.setAttribute("beanFactory",beanFactory);

    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}
package com.crystal.myssm;

import com.crystal.exceptions.BaseDAOException;
import com.crystal.exceptions.DispatcherServletException;
import com.crystal.ioc.BeanFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author crystal
 * @create 2023-02-05 15:16
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

    private BeanFactory beanFactory;

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        ServletContext servletContext = getServletContext();
        Object beanFactoryObj = servletContext.getAttribute("beanFactory");
        if (beanFactoryObj != null){
            beanFactory = (BeanFactory) beanFactoryObj;
        }
    }


    @Override       
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController

        Object beanObj = beanFactory.getObj(servletPath);

//        获取前端的参数operate
        String operate = request.getParameter("operate");
        if (operate == null){
            operate = "index";
        }

//        根据反射调用方法
        try {
//           获取方法的参数列表
            Method[] methods = beanObj.getClass().getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                if (operate.equals(method.getName())){
                    Parameter[] parameters = method.getParameters();
                    Object[] parameterVals = new Object[parameters.length];
                    for (int j = 0; j < parameters.length; j++) {
                        Parameter parameter = parameters[j];
                        String parameterName = parameter.getName();
                        if ("request".equals(parameterName)){
                            parameterVals[j] = "request";
                        }else if ("response".equals(parameterName)){
                            parameterVals[j] = "response";
                        }else if ("session".equals(parameterName)){
                            parameterVals[j] = request.getSession();
                        }else{
                            String parameterval = request.getParameter(parameterName);
                            parameterVals[j] = parameterval;
                            Class<?> parameterType = parameter.getType();
                            Object parameterObj = parameterVals[j];
                            if (parameterObj != null){
                                if ("java.lang.Integer".equals(parameterType)){
                                    parameterObj = Integer.parseInt(parameterval);
                                }
                                parameterVals[j] = parameterObj;
                            }
                        }
                    }
             if (method != null){
//                调用controller中对应的方法
                method.setAccessible(true);
                Object ObjStr = method.invoke(beanObj,parameterVals);

//                视图处理
                String returnStr = (String) ObjStr;
                if (returnStr.startsWith("redirect:")){
                    String redirectVal = returnStr.substring("redirect:".length());
                    response.sendRedirect(redirectVal);
                }else{
                    super.processTemplate(returnStr,request,response);
                }
            }else{
                throw new RuntimeException("operate的值非法!");
            }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new DispatcherServletException("DispatcherServlet出错了。。。");
        }
    }
}

ServletContext应用-待更新

后续更新...