JavaWEB十四:Servlet优化3 增加监听器和过滤器的优化

Servlet优化3 增加监听器和过滤器的优化

一、过滤器Filter
  1. Fileter也属于Servlet规范

  2. Filter开发步骤:新建一个Filter接口的实现类,在类中重写三个方法:init、doFilter、destroy

  3. 配置Filter:

    3.1 注解@WebFilter(" ")

    3.2 xml文件:

  4. 过滤器链

    采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的字母顺序进行排序的

    采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序

  5. 作用

    保证事务的原子性,确保线程安全

  6. 增加过滤器的逻辑图

    在这里插入图片描述

二、ThreadLocal
  1. 本地线程,可以避免多线程中的共享变量出现赋值混乱问题,且一个本地线程只能保存一个共享变量

  2. set方法:在当前线程上存储数据

    // set方法源码
    public  class ThreadLocal<T> {
    	public void set(T value) {
            // 1.获取当前线程
            Thread t = Thread.currentThread();
            // 2.每个线程都维护着一个自己独有的容器(ThreadLocalMap)
            ThreadLocalMap map = getMap(t);
            // 3.如果容器不为空,则将当前的值传入,this代表的此ThreadLocal对象
            if (map != null)
                map.set(this, value);
            // 4.如果容器为空,则创建一个容器    
            else
                createMap(t, value);
        }
    }
    
  3. get方法:获取存储在该线程上的数据

    // get方法源码
    public  class ThreadLocal<T> {
    	public T get() {
            // 1.获取当前线程
            Thread t = Thread.currentThread();
            // 2.获取当前线程对应的容器
            ThreadLocalMap map = getMap(t);
            // 3.如果容器不为空,则获取该ThteadLocal对象对应的共享变量
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                // 4.如果该共享变量不为空,则取出该共享变量的值,并返回
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
    }
    
三、监听器
  1. 监听器分类

    ServletContextListener:监听ServletContext对象的创建和销毁过程

    HttpSessionListener:监听HttpSession对象的创建和销毁过程

    ServletRequestListener:监听ServletRequest对象的创建和销毁过程

    ServletContextAttributeListener:监听ServletContext的保存作用域的改动(add、remove、replace)

    HttpSessionAttributeListener:监听HttpSession的保存作用域的改动(add、remove、replace)

    ServletRequestAttributeListener:监听ServletRequest的保存作用域的改动(add、remove、replace)

    HttpSessionBindingListener:监听某个对象在Session域中的创建与移除

    HttpSessionActivationListener:监听某个对象在Session域中的序列化与反序列化

四、web全面优化
  1. web的全部文件配置图

    在这里插入图片描述

  2. web各部分的执行顺序图

    在这里插入图片描述

五、优化后的所有程序
  1. 监听器Listener
    @WebListener
    public class ContextLoaderListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            // 获取Servlet上下文(application)作用域
            ServletContext application = servletContextEvent.getServletContext();
            // 获取web.xml文件内的context参数
            String path = application.getInitParameter("contextConfigLocation");
            // 将获取的参数传入IOC内
            BeanFactory beanFactory = new ClassPathXmlApplication(path);
            // 将beanFactory保存到application作用域中
            application.setAttribute("beanFactory",beanFactory);
        }
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
    		// 监听销毁过程
        }
    }
    
  2. 创建Filter过滤层,完善事务执行逻辑
    @WebFilter("*.do")
    public class OpenFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            try {
                ((HttpServletRequest)servletRequest).setCharacterEncoding("UTF-8");
                TransactionManager.beginTransaction();
                System.out.println("开启事务");
                filterChain.doFilter(servletRequest,servletResponse);
                TransactionManager.commitTransaction();
                System.out.println("提交事务");
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                try {
                    TransactionManager.rollbackTransaction();
                    System.out.println("回滚事务");
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        @Override
        public void destroy() {
    
        }
    }
    
  3. 创建事务管理类
    public class TransactionManager {
        public static void beginTransaction() throws SQLException {
            JdbcUtils.getConnection().setAutoCommit(false);
        }
        public static void commitTransaction() throws SQLException {
            Connection conn = JdbcUtils.getConnection();
            conn.commit();
            JdbcUtils.closeConn();
        }
        public static  void  rollbackTransaction() throws SQLException {
            Connection conn = JdbcUtils.getConnection();
            conn.rollback();
            JdbcUtils.closeConn();
        }
    }
    
  4. 改造JdbcUtil工具类,增加ThreadLocal对象,确保事务的原子性
    public class JdbcUtils {
        // 1.新建ThreadLocal属性
        private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
        // 2.创建Connection对象的方法
        public static Connection createConnection()  {        
            try {
                InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
                Properties ps = new Properties();
                ps.load(is);
                String url = ps.getProperty("url");
                String user = ps.getProperty("user");
                String password = ps.getProperty("password");
                String driver = ps.getProperty("driver");
                // 2.注册驱动
                Class.forName(driver);
                // 3.创建连接
                Connection conn = DriverManager.getConnection(url, user, password);
                return conn;
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return null;
        }
    	// 3.在threadLocal对象的基础上获取Connection对象,确保其在不同的线程中保持独立性
        public static Connection getConnection() {
            Connection conn = threadLocal.get();
            if (conn == null) {
               conn = createConnection();
               threadLocal.set(conn);
            }
            return threadLocal.get();
        }
        // 4.通用关闭程序1
        public static void closeResource(Connection conn, Statement ps) {
            try {
                if (ps != null) {
                    ps.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    
        // 5.通用关闭程序2
        public static void closeResource(Connection conn, Statement ps, ResultSet rs) {
            try {
                if (ps != null) {
                    ps.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        // 6.使用threadLocal对象的关闭程序
        public static void closeConn() throws SQLException {
            Connection conn = threadLocal.get();
            if (conn == null) {
                return ;
            }
            if (!conn.isClosed()) {
                conn.close();
                threadLocal.set(null);
            }
        }
    }
    
  5. 业务层,解析xml配置文件的各标签信息,并组装各依赖关系
    public class ClassPathXmlApplication implements BeanFactory{
        private Map<String,Object> beanMap = new HashMap<>();
        public ClassPathXmlApplication() {
            this("applicationContext.xml");
        }
        public ClassPathXmlApplication(String path) {
            try {
                InputStream is = getClass().getClassLoader().getResourceAsStream(path);
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document document = builder.parse(is);
                // 获取bean节点
                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 beanId = beanElement.getAttribute("id");
                        String className = beanElement.getAttribute("class");
                        // 获取class对应的类的实例对象
                        Class beanClass = Class.forName(className);
                        Object beanObj = beanClass.newInstance();
                        // beanMap中存储的是id的变量名和class对应的类的实例对象
                        beanMap.put(beanId,beanObj);
                        // 上述只是将bean标签全部保存到了beanMap中,接下来进行bean之间依赖关系的配置
                    }
                }
                // 组装bean之间的依赖关系
                for (int i = 0; i < beanNodeList.getLength(); i++) {
                    Node beanNode = beanNodeList.item(i);
                    // 如果该节点的类型是否为元素节点
                    if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                        // 如果是元素节点,就将其从Node节点类型强转为Element元素节点类型
                        Element beanElement = (Element) beanNode;
                        String beanId = beanElement.getAttribute("id");
                        NodeList childNodesList = beanElement.getChildNodes();
                        for (int j = 0; j < childNodesList.getLength(); j++) {
                            // 取其中一个
                            Node beanChildNode = childNodesList.item(j);
                            if (beanChildNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName()) ){
                                Element beanChildElement = (Element)beanChildNode;
                                String propertyName = beanChildElement.getAttribute("name");
                                String propertyRef = beanChildElement.getAttribute("ref");
                                // 得到propertyRef对应的实例,ref对应其它bean的id
                                Object beanRef = beanMap.get(propertyRef);
                                // 得到当前beanId对应得对象
                                Object beanObj = beanMap.get(beanId);
                                // 通过反射,获取当前bean中class的对象中与propertyName同名的属性
                                Class beanObjClazz = beanObj.getClass();
                                Field propertyField = beanObjClazz.getDeclaredField(propertyName);
                                propertyField.setAccessible(true);
                                // 将与ref同名的id对应的bean标签中的class对象赋值给该属性
                                propertyField.set(beanObj,beanRef);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        @Override
        public Object getBean(String id) {
            return beanMap.get(id);
        }
    }
    
  6. 调度型的Servlet组件,将拦截到的各请求分配至对应的实现功能体
    @WebServlet("*.do")
    public class DispatcherServlet extends ViewBaseServlet{
        private BeanFactory beanFactory;
        // 一、在构造器中解析相关联的xml配置文件,获取请求标识与servlet组件的全类名的实例对象
        @Override
        public void init() throws ServletException {
            super.init();
            beanFactory = new ClassPathXmlApplication();
        }
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws  IOException {
    
            // 二、解析出请求路径中的请求标识
            /*
                1.获取servlet请求路径,来自tomcat的url配置或html/js文件内的url配置
                  假设:url = "http://localhost.8080/optimization_2/customers.do"
                  那么:ServletPath = "/customers.do"
            */
            System.out.println("调度层Servlet执行service");
            String servletPath = req.getServletPath();
            // 2.获取最后出现该后缀名字符串的索引值
            int lastDotIndex = servletPath.lastIndexOf(".do");
            /*
                3.使用String substring(int beginIndex, int endIndex)方法,将servletPath头部的斜杠和后缀的.do去除
                  servletPath.substring(1):表示从索引1处开始,故索引0处的值就被截取掉了
            */
            servletPath = servletPath.substring(1,lastDotIndex);
    
            // 三、通过从在请求路径中解析出的请求标识,传入beanMap中,即可获取对应的controller(组件)
            Object controllersObj = beanFactory.getBean(servletPath);
            // 1.通过req获取html/js文件内的operate的值
            String operate = req.getParameter("operate");
            // 2.如果operate的值为空,就赋初始值index
            if (StringUtil.isEmpty(operate)) {
                operate = "index";
            }
            // 3.使用反射,从beanMap中得到的指定Controller类内与operate匹配的方法
            try {
                Method[] methods = controllersObj.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if (operate.equals(method.getName())) {
                        Parameter[] parameters = method.getParameters();
                        // 创建一个Object数组,用于存放通过反射得到的各参数的对应值
                        Object[] parameterValues = new Object[parameters.length];
                        for (int i = 0; i < parameters.length; i++) {
                            Parameter p = parameters[i];
                            // 使用Parameter类的getName方法,获取该索引值对应参数的名称
                            String parameterName = p.getName();
                            // 将这些参数名赋给parameterValues数组
                            if ("req".equals(parameterName)) {
                                parameterValues[i] = req;
                            } else if ("resp".equals(parameterName)) {
                                parameterValues[i] = resp;
                            } else if ("session".equals(parameterName)) {
                                parameterValues[i] = req.getSession();
                            } else {
                                String parameterValue = req.getParameter(parameterName);
                                parameterValues[i] = parameterValue;
                            }
                        }
                        method.setAccessible(true);
                        Object returnObj = method.invoke(controllersObj, parameterValues);
                        // 5.视图处理
                        // 5.1 获取该方法返回的重定向字符串
                        String retrunStr = (String) returnObj;
                        // 5.2 截取重定向内字符串内包含的请求路径(例如:index.do)
                        if (retrunStr.startsWith("redirect:")) {
                            String redirectStr = retrunStr.substring("redirect:".length());
                            resp.sendRedirect(redirectStr);
                            System.out.println("调度层执行redirect");
                        } else {
                            // 5.3 将controller内返回的模板传入父类的模板处理方法
                            System.out.println("调度层执行 - processTemplate");
                            super.processTemplate(retrunStr,req,resp);
                        }
    
                    }
                }
            }  catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
  7. 去掉close功能的BaseDAO
    /**
     * @author e_n
     * @version 1.0.0
     * @ClassName BaseDAO.java
     * @Description 优化后的BaseDAO,可以利用泛型进行通用化,简化内方法的调用
     * @CreateTime 2022/01/30 16:13
     */
    public abstract class BaseDAO<T> {
        private Class<T> clazz = null;
        // 在代码块中对clazz进行赋值,当前对象的父类的泛型
        {
            // this是该类的实例对象
            Type genericSuperclass = this.getClass().getGenericSuperclass();
            ParameterizedType paramType = (ParameterizedType) genericSuperclass;
            Type[] typeArguments = paramType.getActualTypeArguments();
            clazz = (Class<T>) typeArguments[0];
        }
        
        // 通用的增删改查方法
        public int update(Connection conn, String sql, Object...args) {
            System.out.println("Dao - update");
            PreparedStatement ps = null;
            try {
                // 1.sql预编译
                ps = conn.prepareStatement(sql);
                // 2.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i+1,args[i]);
                }
                // 3.执行sql
                return ps.executeUpdate();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return 0;
        }
       
        // 通用的多结果查询方法
        public List<T> CommonRetrieve(Connection conn, String sql, Object...args)  {
            System.out.println("Dao - 通用查询");
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                // 1.预编译sql,生成PreparedStatement对象
                ps = conn.prepareStatement(sql);
                // 2.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i+1,args[i]);
                }
                // 3.执行并返回结果集
                rs = ps.executeQuery();
                // 4.处理结果集
                // 4.1 创建该结果集的元数据,通过元数据获取结果集中数据的信息
                ResultSetMetaData rsmd = rs.getMetaData();
                // 4.2 获取结果集中列的个数
                int columnCount = rsmd.getColumnCount();
                // 4.3 创建用于存储结果集中多条记录的集合
                ArrayList<T> tSet = new ArrayList<>();
                while (rs.next()) {
                    // 4.4 处理该行记录的每一个字段
                    // 4.4.1 创建该行记录在JavaBean中类的对象,此处用泛型实现
                    T t = clazz.newInstance();
                    // 4.4.2 利用通过元素据获得的结果集中列的个数,结合for循环对结果集中的列进行遍历
                    for (int i = 0; i < columnCount; i++) {
                        // 4.4.3 通过结果集对象获取该字段的值
                        Object columnValue = rs.getObject(i + 1);
                        // 4.4.4 通过元素据获取该字段的别(列)名,该列名与该行记录对应的对象中的属性名相同
                        String columnLabel = rsmd.getColumnLabel(i+1);
                        // 4.4.5 通过反射,给Customers对象中对应的属性赋值,实现将结果集中的数据存储到对象中
                        Field field = clazz.getDeclaredField(columnLabel);
                        // 确保私有属性可以访问
                        field.setAccessible(true);
                        // 给该字段对应的属性赋值
                        field.set(t,columnValue);
                    }
                    // 4.4.6 将此次循环产生的对象加入新建的集合中
                    tSet.add(t);
                }
                return tSet;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        // 通用的单结果查询方法
        public T singleCommonRetrieve(Connection conn, String sql, Object...args)  {
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                // 1.预编译sql,生成PreparedStatement对象
                ps = conn.prepareStatement(sql);
                // 2.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i+1,args[i]);
                }
                // 3.执行并返回结果集
                rs = ps.executeQuery();
                // 4.处理结果集
                // 4.1 创建该结果集的元数据,通过元数据获取结果集中数据的信息
                ResultSetMetaData rsmd = rs.getMetaData();
                // 4.2 获取结果集中列的个数
                int columnCount = rsmd.getColumnCount();
                if (rs.next()) {
                    // 4.3 处理该行记录的每一个字段
                    // 4.3.1 创建该行记录在JavaBean中类的对象,此处用泛型实现
                    T t = clazz.newInstance();
                    // 4.3.2 利用通过元素据获得的结果集中列的个数,结合for循环对结果集中的列进行遍历
                    for (int i = 0; i < columnCount; i++) {
                        // 4.3.3 通过结果集对象获取该字段的值
                        Object columnValue = rs.getObject(i + 1);
                        // 4.3.4 通过元素据获取该字段的别(列)名,该列名与该行记录对应的对象中的属性名相同
                        String columnLabel = rsmd.getColumnLabel(i+1);
                        // 4.3.5 通过反射,给Customers对象中对应的属性赋值,实现将结果集中的数据存储到对象中
                        Field field = clazz.getDeclaredField(columnLabel);
                        // 确保私有属性可以访问
                        field.setAccessible(true);
                        // 给该字段对应的属性赋值
                        field.set(t,columnValue);
                    }
                return t;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        
        // 用于查询特殊值的通用方法(聚合函数)
        public <E> E getValue(Connection conn, String sql, Object...args) {
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                // 1.sql预编译
                ps = conn.prepareStatement(sql);
                // 2.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i+1,args[i]);
                }
                // 3.执行sql
                rs = ps.executeQuery();
                // 4.返回值
                if (rs.next()) {
                    return (E) rs.getObject(1);
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return null;
        }
    }
    
  8. controller:实现各请求功能的方法集
    public class CustomersController {
        private CustomersServiceImpl cService = null;
    
        protected String index(String oper,String keyword,String page,HttpServletRequest req) {
            System.out.println("Controller层 - index");
            Connection conn = null;
            try {
                conn = JdbcUtils.getConnection();
                HttpSession session = req.getSession();
                int pageNo = 1;
                if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
                    pageNo = 1;
                    if (StringUtil.isEmpty(keyword)) {
                        keyword = "";
                    }
                    session.setAttribute("k",keyword);
                }else {
                    Object keyObj = session.getAttribute("k");
                    if (keyObj == null) {
                        keyword =  "";
                    }else {
                        keyword = (String) keyObj;
                    }
                }
                if (page != null) {
                    pageNo = Integer.parseInt(page);
                }
                session.setAttribute("pageOn",pageNo);
                List<Customers> custList = cService.getList(conn,"%"+ keyword +"%",pageNo);
                session.setAttribute("cl",custList);
                long count = 0L;
                count = cService.getCount(conn,"%"+keyword+"%");
                int max = (int) (count+2-1)/2;
                session.setAttribute("max",max);
                return "index";
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private String add(String name,String email,String birth)  {
            System.out.println("Controller层 - add");
            Connection conn = null;
            try {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                Date date = format.parse(birth);
                conn = JdbcUtils.getConnection();
                cService.addCustomer(conn,name,email,date);
                System.out.println("add执行");
                return "redirect:customers.do";
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private String delete(String sid)  {
            if (StringUtil.isNotEmpty(sid)) {
                Connection conn = null;
                try {
                    int id = Integer.parseInt(sid);
                    conn = JdbcUtils.getConnection();
                    cService.delById(conn,id);
                    return "redirect:customers.do";
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
        private String edit(String cid,HttpServletRequest req)  {
            Connection conn = null;
            try {
                conn = JdbcUtils.getConnection();
                if (StringUtil.isNotEmpty(cid)) {
                    int id = Integer.parseInt(cid);
                    Customers customer = cService.getCustomerById(conn, id);
                    req.setAttribute("cu" ,customer);
                    return "edit";
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private String update(String id,String name,String email,String birth) {
            Connection conn = null;
            try {
                int idInt = Integer.parseInt(id);
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                Date date = format.parse(birth);
                conn = JdbcUtils.getConnection();
                cService.updateById(conn,name,email,date,idInt);
                return "redirect:customers.do";
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
  9. service:各业务的实现类
    public class CustomersServiceImpl implements CustomersService {
        private ListIpm baseDAO = null;
        @Override
        public List<Customers> getList(Connection conn, String str, int pageOn) {
            return baseDAO.getList(conn,str,pageOn);
        }
    
        @Override
        public void addCustomer(Connection conn, String name, String email, Date date) {
            baseDAO.addCustomer(conn,name,email,date);
        }
    
        @Override
        public Customers getCustomerById(Connection conn, int id) {
            return baseDAO.getCustomerById(conn,id);
        }
    
        @Override
        public void delById(Connection conn, int id) {
            baseDAO.delById(conn,id);
        }
    
        @Override
        public Long getCount(Connection conn, String str) {
            return baseDAO.getCount(conn,str);
        }
    
        @Override
        public void updateById(Connection conn, String name, String email, Date date, int id) {
            baseDAO.updateById(conn, name, email, date, id);
        }
    }
    
  10. 具体数据表的DAO实现类
    public class ListIpm extends BaseDAO<Customers> implements ListDAO{
        @Override
        public List<Customers> getList(Connection conn ,String str,int pageOn) {
            String sql = "select cust_name name,cust_email email,cust_birth birth,cust_id id from customers where " +
                    "cust_email like ? limit ? , 2";
            return super.CommonRetrieve(conn, sql,str,(pageOn-1)*2);
        }
    
        @Override
        public Customers getCustomerById(Connection conn,int id) {
            String sql = "select cust_name name,cust_email email,cust_birth birth,cust_id id from customers where cust_id" +
                    " = ?";
            return super.singleCommonRetrieve(conn,sql,id);
        }
    
        @Override
        public void updateById(Connection conn, String name, String email, Date date, int id) {
            String sql = "update customers set cust_name = ? , cust_email= ? , cust_birth = ? where cust_id = ?";
            super.update(conn,sql,name,email,date,id);
        }
    
        @Override
        public void delById(Connection conn,  int id) {
            String sql = "delete from customers where cust_id = ?";
            super.update(conn,sql,id);
        }
    
        @Override
        public void addCustomer(Connection conn, String name, String email, Date date) {
            String sql = "insert into customers values(0,? , ? , ?)";
            super.update(conn,sql,name,email,date);
        }
    
        @Override
        public Long getCount(Connection conn,String str) {
            String sql = "select count(*) from customers where cust_email like ?";
            return super.getValue(conn, sql,str);
        }
    }
    
  11. pojo:单行数据的模型类
    public class Customers {
        private int id;
        private String name;
        private String email;
        private java.util.Date birth;
    
        public Customers() {
        }
    
        public Customers(int id, String name, String email, java.util.Date birth) {
            this.id = id;
            this.name = name;
            this.email = email;
            this.birth = birth;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public java.util.Date getBirth() {
            return birth;
        }
    
        public void setBirth(java.util.Date birth) {
            this.birth = birth;
        }
    }
    
  12. 配置文件
    applicationContext.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <!-- 新建一个beans标签,在该标签内,对每个bean进行具体配置 -->
    <beans>
        <bean id="customersDAO" class="com.atguigu.consrumers.dao.ListIpm"/>
        <bean id="customersService" class="com.atguigu.consrumers.service.impl.CustomersServiceImpl" >
            <!--
                property标签用来表示属性:name表示该类内的属性名;ref表示引用其它bean的id值
                建立了service层和DAO层之间的关联
            -->
            <property name="baseDAO" ref="customersDAO" />
        </bean>
        <bean id="customers" class="com.atguigu.consrumers.controllers.CustomersController" >
            <!-- 建立controller层和service层之间的关联 -->
            <property name="cService" ref="customersService"/>
        </bean>
    </beans>
    
    jdbc.properties
    user=root
    password=********
    url=jdbc:mysql://localhost:3306/test02_market?rewriteBatchedStatements=true&serverTimezone=UTC&useSSL=false
    driver=com.mysql.cj.jdbc.Driver
    
    web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <context-param>
            <param-name>view-prefix</param-name>
            <param-value>/</param-value>
        </context-param>
        <context-param>
            <param-name>view-suffix</param-name>
            <param-value>.html</param-value>
        </context-param>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>applicationContext.xml</param-value>
        </context-param>
    <!--
        <listener>
            <listener-class>com.atguigu.myssm.listener.ContextLoaderListener</listener-class>
        </listener>
    -->
    </web-app>
    
  13. html / css / js 文件

    参考:JavaWEB十:Servlet优化1 实现将各种请求由一个组件进行统一调度后响应_e_nanxu的博客-CSDN博客

五、出现过的bug
  1. html关联css时,其标签中的路径一定要同tomcat中的Application Context一样,不能写成模块名

    在这里插入图片描述

  2. 加入过滤层,进行事务管理后,除了事务管理中进行数据库的conn关闭,要清除掉其它类中的方法中所有对conn关闭的程序,从而保证事务的原子性,否则会报错
    java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.
    
参考资料
  1. Java中的ThreadLocal详解 - 夏末秋涼 - 博客园 (cnblogs.com)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

e_nanxu

感恩每一份鼓励-相逢何必曾相识

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值