单例模式及统一异常处理
文章目录
- 单例模式及统一异常处理
- 一、学习目标与任务
- 二、单例模式
- 三、搭建项目运行环境
- 3.1.实现步骤
- 3.2.改造登录、注销功能
- 3.3.改造CVS-用户登录功能
- 3.3.1 web.xml配置
- 3.3.2 applicationContext-jdbc.xml配置
- 3.3.3 springmvc-servlet配置
- 3.3.4 database.properties文件
- 3.3.5 log4j.properties文件
- 3.3.6 SysUserDao
- 3.3.7 ConfigManager
- 3.3.8 BaseDao
- 3.3.9 SysUserDaoImpl
- 3.3.10 SysUserService
- 3.3.11 SysUserServiceImpl
- 3.3.12 SysUserController
- 3.3.13 login.jsp
- 3.3.14 frame.jsp
- 3.3.15 common/head.jsp
- 3.3.16 common/foot.jsp
- 3.3.17 maven pom.xml配置
- 3.3.18 Constants 系统静态常量
- 四、静态资源文件的引用
- 五、异常处理
- 六、改造用户列表查询功能
- 七、本章总结
- 八、监听器
一、学习目标与任务
1.1回顾提问:
1.MVC设计模式是什么?
2.Spring MVC的架构是什么?
3.Spring MVC的请求处理流程是什么?
4.Spring MVC框架是基于哪个核心的Servlet?
5.Spring MVC如何实现View与Controller之间的参数传递?
1.2学习目标
- 掌握并理解单例模式
- 搭建SSM框架
- 掌握Spring MVC访问静态文件
- 掌握Servlet API作为控制器接口入参
- 掌握Spring MVC异常(局部、全局)处理
1.3学习任务
- 改造读取数据库配置文件的工具类为单例模式
- 改造724系统-登录、注销、查询用户列表功能
- 使用Spring MVC(局部)异常处理,提示登录失败的原因
- 使用Spring MVC(全局)异常处理,提示登录失败的原因
- 改造724系统-供货商列表查询功能
二、单例模式
1.1.问题分析
- 回顾学习JDBC操作数据库的基类(BaseDao.java)
- database.properties文件
driver=com.mysql.cj.jdbc.Driver #在和mysql传递数据的过程中,使用unicode编码格式,字符集设置为utf-8,并根据需要设置时区 url=jdbc:mysql://127.0.0.1:3306/cvs_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai user=root password=root
- ConfigManager工具类:
package cn.cvs.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //存在问题:每个线程操作数据库都需new一个BaseDao实例,即每个线程都会单独加载配置文件,影响系统性能 public class ConfigManager { private static Properties properties; static{ init(); } public static void init(){ String configFile = "database.properties"; properties = new Properties(); InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream(configFile); try { properties.load(is); is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static String getProperty(String key){ return properties.getProperty(key); } }
- BaseDao工具类:
package cn.cvs.dao; import cn.cvs.utils.ConfigManager; import java.sql.*; /** * 操作数据库的基类--静态类 * @author Aiden * */ public class BaseDao { /** * 获取数据库连接对象 * @return */ public static Connection getConnection(){ Connection connection = null; String driver = ConfigManager.getProperty("driver"); String url = ConfigManager.getProperty("url"); String user = ConfigManager.getProperty("user"); String password = ConfigManager.getProperty("password"); try { Class.forName(driver); connection = DriverManager.getConnection(url, user, password); } catch (Exception e) { e.printStackTrace(); } return connection; } /** * 查询操作 */ public static ResultSet execute(Connection connection,PreparedStatement pstm,ResultSet rs, String sql,Object[] params) throws Exception{ pstm = connection.prepareStatement(sql); for(int i = 0; i < params.length; i++){ pstm.setObject(i+1, params[i]); } rs = pstm.executeQuery(); return rs; } /** * 更新操作 */ public static int execute(Connection connection,PreparedStatement pstm, String sql,Object[] params) throws Exception{ int updateRows = 0; pstm = connection.prepareStatement(sql); for(int i = 0; i < params.length; i++){ pstm.setObject(i+1, params[i]); } updateRows = pstm.executeUpdate(); return updateRows; } /** * 释放资源 */ public static boolean closeResource(Connection connection,PreparedStatement pstm,ResultSet rs){ boolean flag = true; if(rs != null){ try { rs.close(); rs = null;//GC回收 } catch (SQLException e) { e.printStackTrace(); flag = false; } } if(pstm != null){ try { pstm.close(); pstm = null;//GC回收 } catch (SQLException e) { e.printStackTrace(); flag = false; } } if(connection != null){ try { connection.close(); connection = null;//GC回收 } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); flag = false; } } return flag; } }
问题1:
- BaseDao:操作数据库的基类
- init()方法
- 从配置文件中读取数据库连接的初始化参数
- 读取配置文件属于I/O操作,十分消耗资源,影响系统性能
- 每个线程操作数据库都需new一个BaseDao实例,即每个线程都会单独加载配置文件,影响系统性能,该如何解决呢?
分析:
- 对于每个线程,可共享一个实例
- 单例模式
1.2单例模式的概念
单例模式:系统运行期间,有且仅有一个实例
一个类只有一个实例
- 私有构造方法
自行创建实例对象
- 定义了静态的该类私有对象
对外提供实例对象
- 提供一个静态的公有方法,返回创建的或者获取本身的静态私有对象
1.3单例模式实现的方式
1.3.1简单的单例模式实现
package cn.cvs.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //通过单例模式读取配置文件 public class ConfigManager { //1.定义静态实例属性 private static ConfigManager configManager; private static Properties properties; //2.私有构造器-读取数据库配置文件 private ConfigManager(){ String configFile = "database.properties"; properties = new Properties(); InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream(configFile); try { properties.load(is); is.close(); } catch (IOException e) { e.printStackTrace(); } } //3.对外提供的获取ConfigManager实例的方法 public static ConfigManager getInstance(){ if(configManager == null){ configManager = new ConfigManager(); } return configManager; } public String getValue(String key){ return properties.getProperty(key); } }
问题2:
- 在并发环境下,上述的单例模式实现是否存在弊端,线程是否安全?是否会出现多个configManager实例?
分析:
- 懒汉模式
- 饿汉模式
1.3.2懒汉模式-
synchronized
懒汉模式:
类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例
特点
线程不安全
延迟加载(Lazy Loading)
如何解决线程安全问题?
synchronized关键字
在方法中添加 synchronized 关键字:
public static synchronized ConfigManager getInstance()
package cn.cvs.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //通过单例模式读取配置文件 public class ConfigManager { private static ConfigManager configManager; private static Properties properties; //私有构造器-读取数据库配置文件 private ConfigManager(){ String configFile = "database.properties"; properties = new Properties(); InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream(configFile); try { properties.load(is); is.close(); } catch (IOException e) { e.printStackTrace(); } } // 对外提供的获取ConfigManager实例的方法 public static synchronized ConfigManager getInstance(){ if(configManager == null){ configManager = new ConfigManager(); } return configManager; } public String getValue(String key){ return properties.getProperty(key); } }
1.3.3饿汉模式
- 类加载的时候,就完成初始化
- 特点
- 线程安全
- 不具备延迟加载特性
饿汉模式示例
- 直接创建实例对象:
private static ConfigManager configManager = new ConfigManager();
- 定义获取实例对象的方法getInstance:
public static ConfigManager getInstance()
package cn.cvs.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //通过单例模式读取配置文件 public class ConfigManager { private static ConfigManager configManager = new ConfigManager(); private static Properties properties; //私有构造器-读取数据库配置文件 private ConfigManager(){ String configFile = "database.properties"; properties = new Properties(); InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream(configFile); try { properties.load(is); is.close(); } catch (IOException e) { e.printStackTrace(); } } /*//全局访问点-(懒汉模式) public static synchronized ConfigManager getInstance(){ if(configManager == null){ configManager = new ConfigManager(); } return configManager; }*/ //饿汉模式 public static ConfigManager getInstance(){ return configManager; } public String getValue(String key){ return properties.getProperty(key); } }
问题3:
- 若实例化单例类(比如说:ConfigManager)很消耗资源,我们希望它可以延迟加载,即不想让它在类加载的时候就实例化,应该如何处理呢?
分析:
要求饿汉模式同时要具备延迟加载的特性
静态内部类
1.3.4饿汉模式-静态内部类
- 定义Single类,在类的内部增加内部静态类 SingleHelper
package cn.cvs.utils; public class Single { private static Single single; //私有化构造 private Single(){ // 整个运行期间,只执行一次的业务代码操作,如:读取配置文件的操作。 //...... } public static class SingleHelper{ private static final Single INSTANCE = new Single(); } //对外提供获取本实例的方法 public static Single getInstance(){ single = SingleHelper.INSTANCE; return single; } public static Single test(){ return single; } }
- 测试分别使用Single.test(); 与Single.getInstance();获取对象
package cn.cvs.utils; public class TestSingle { public static void main(String[] args) { Single single = Single.test(); System.out.println("调用Singleton.test()方法获取实例对象:" + single); single = Single.getInstance(); System.out.println("第一次调用Singleton.getInstance()方法获取实例对象:" + single); single = Single.getInstance(); System.out.println("第二次调用Singleton.getInstance()方法获取实例对象:" + single); } }
- 运行结果:
学员操作—增加读取数据库配置文件的工具类
需求说明:
- 在上章学员操作的基础上增加ConfigManager.java的工具类完成数据库配置文件的读取
- 该类设计为单例模式,使用懒汉模式、饿汉模式、静态内部类等方式均可,但需要考虑线程安全问题。
1.4.Spring MVC中的单例模式
Spring MVC-Controller
- 默认scope为singleton
- 速度和性能优越
在Spring MVC的Controller中声明成员变量,需要注意线程安全问题
一般情况下,Controller内的成员变量就只有service对象
package cn.cvs.controller; import cn.cvs.pojo.SysUser; import org.apache.log4j.Logger; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @Controller @RequestMapping("/user") @Scope("prototype")//默认scope为singleton public class SysUserController { private Logger logger = Logger.getLogger(SysUserController.class); private ArrayList<SysUser> userList = new ArrayList<SysUser>(); // 用于返回查询到的用户数据 private ArrayList<SysUser> queryUserList = new ArrayList<SysUser>(); public SysUserController(){ userList.add(new SysUser(5,"zhaojing","赵静","5555555",1 , "13054784445","上海市宝山区",1,1,new Date(),1, new Date())); userList.add(new SysUser(4,"wanglin","王林","4444444",1 ,"18965652364","北京市学院路",1,1,new Date(),1,new Date())); userList.add(new SysUser(1,"test001","测试用户001","1111111",1 , "13566669998","北京市朝阳区",1,1,new Date(),1, new Date())); userList.add(new SysUser(2,"zhaoyan","赵燕","2222222",1 , "18678786545","北京市海淀区",1,1,new Date(),1, new Date())); userList.add(new SysUser(3,"test003","测试用户003","1111111",1 ,"13121334531","北京市海淀区",1,1,new Date(),1,new Date())); } /** * 查询用户列表 * @param model * @return */ @GetMapping("/list") public String list(Model model){ logger.info("当查询条件位空时,查询用户信息" + this); queryUserList.clear(); queryUserList.addAll(userList); model.addAttribute("queryUserList",userList); return "sysUser/sysUserList"; } /** * 根据用户名称查询用户列表 * @param realName * @param model * @return */ @PostMapping("/list") public String list(@RequestParam(value="realName",required=false) String realName, Model model){ logger.info("查询条件:【realName】= " + realName +", 查询用户信息"); queryUserList.clear(); if(realName != null && !realName.equals("")){ for(SysUser user:userList){ if(user.getRealName().indexOf(realName) != -1){ queryUserList.add(user); } } }else{ queryUserList.addAll(userList); } model.addAttribute("queryUserList",queryUserList); return "sysUser/sysUserList"; } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>查询用户信息</title> </head> <body> <h1>查询用户列表</h1> <form action="${pageContext.request.contextPath }/user/list" method="post"> 用户名称:<input type="text" name="realName" value=""/> <input type="submit" name="查询"/> </form> <c:forEach var="sysUser" items="${queryUserList }"> <div> id= ${sysUser.id }; 用户编码= ${sysUser.account }; 用户名称= ${sysUser.realName }; 用户密码= ${sysUser.password }; 用户地址= ${sysUser.address }; </div> </c:forEach> </body> </html>
- 注意当控制器获取视图传递的值出现乱码时需要配置过滤器
<!-- 配置编码方式过滤器,注意一点:要配置在所有过滤器的前面 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
三、搭建项目运行环境
3.1.实现步骤
添加框架整合所依赖的jar包
- Spring、Spring MVC框架对应的jar包
拆分配置文件
- 创建Spring配置文件,用来处理Service层和Dao层的相关功能
配置web.xml文件
- ContextLoaderListener监听器
- 在Web容器启动的时候初始化Spring容器
- contextConfigLocation参数
- 加载指定的配置文件
3.2.改造登录、注销功能
实现步骤:
- 使用@Repository或@Component标注DAO组件
- 使用@Service或@Component标注Service组件
- 使用@Autowired或@Resource为Service注入DAO组件
- 改造Controller层
- 使用@Autowired或@Resource为Controller注入Service组件
- 创建SysUserController,实现以下业务功能:
- 跳转到登录页面
- 登录
- 跳转到首页
- 改造View层
- 静态资源文件 (js、css、images等)
- 用户登录页面(login.jsp)和首页(index.jsp)
- 公共页面(foot.jsp、head.jsp)
3.3.改造CVS-用户登录功能
3.3.1 web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Aiden Create Spring Web MVC</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param> <servlet> <servlet-name>spring-mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>spring-mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
3.3.2 applicationContext-jdbc.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <!-- 使spring扫描包下的所有类,让标注spring注解的类生效--> <!-- 若扫描到有 @Repository、@Service、@Component @Controller 等这些注解的类,则把这些类注册为bean--> <context:component-scan base-package="com.aiden.springmvc.cvs.dao"></context:component-scan> <context:component-scan base-package="com.aiden.springmvc.cvs.service"></context:component-scan> </beans>
3.3.3 springmvc-servlet配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 1.开启注解扫描--> <mvc:annotation-driven/> <!-- 2.使spring扫描controller包下的所有类,让标注@controller注解的类生效 --> <context:component-scan base-package="com.aiden.springmvc.cvs.controller"/> <!-- 3.静态资源映射,可以配置多个 --> <mvc:resources mapping="/statics/**" location="/statics/"/> <!-- 完成视图的对应 --> <!-- 4.对转向页面的路径解析。prefix:前缀, suffix:后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
3.3.4 database.properties文件
driver=com.mysql.cj.jdbc.Driver #在和mysql传递数据的过程中,使用unicode编码格式,字符集设置为utf-8,并根据需要设置时区 url=jdbc:mysql://127.0.0.1:3306/cvs_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai user=root password=root
3.3.5 log4j.properties文件
log4j.rootLogger=debug,CONSOLE,file log4j.logger.cn.cvs=debug log4j.logger.org.apache.ibatis=debug log4j.logger.org.mybatis.spring=debug log4j.logger.java.sql.Connection=debug log4j.logger.java.sql.Statement=debug log4j.logger.java.sql.PreparedStatement=debug log4j.logger.java.sql.ResultSet=debug log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.Threshold=debug log4j.appender.CONSOLE.DatePattern=yyyy-MM-dd log4j.appender.CONSOLE.Target=System.out log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.DatePattern=yyyy-MM-dd log4j.appender.file.File=${springmvc-02.root}/logs/log.log log4j.appender.file.Append=true log4j.appender.file.Threshold=debug log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n log4j.logger.com.opensymphony.xwork2=debug
3.3.6 SysUserDao
package com.aiden.springmvc.cvs.dao; import com.aiden.springmvc.cvs.pojo.SysUser; import java.sql.Connection; import java.util.List; /** * DAO接口 * * @author Aiden */ public interface SysUserDao { /** * 增加用户信息 * * @param connection * @param sysUser 用户对象 * @return * @throws Exception */ int insert(Connection connection, SysUser sysUser) throws Exception; /** * 通过用户编码获取User * * @param connection * @param account * @return * @throws Exception */ SysUser findUserByAccount(Connection connection, String account) throws Exception; /** * 通过条件查询-userList * * @param connection * @param realName 用户名称 * @param userRoleId 角色编号 * @return * @throws Exception */ List<SysUser> findList(Connection connection, String realName, int userRoleId, int currentPageNo, int pageSize) throws Exception; /** * 通过条件查询-用户表记录数 * * @param connection * @param realName 用户名称 * @param userRoleId 角色编号 * @return * @throws Exception */ int getTotalCount(Connection connection, String realName, int userRoleId) throws Exception; /** * 通过用户编号删除user * * @param id * @return * @throws Exception */ int deleteUserById(Connection connection, Integer id) throws Exception; /** * 通过userId获取user * * @param connection * @param id 用户编号 * @return * @throws Exception */ SysUser getUserById(Connection connection, String id) throws Exception; /** * 修改用户信息 * * @param connection * @param user 用户对象 * @return * @throws Exception */ int modify(Connection connection, SysUser user) throws Exception; /** * 修改当前用户密码 * * @param connection * @param id 用户编号 * @param password 用户密码 * @return * @throws Exception */ int updatePwd(Connection connection, int id, String password) throws Exception; }
3.3.7 ConfigManager
package com.aiden.springmvc.cvs.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * @author Aiden * 读取配置文件的工具类-单例模式 * [存在问题]:每个线程操作数据库都需new一个BaseDao实例, * 即每个线程都会单独加载配置文件,影响系统性能。 */ public class ConfigManager { private static ConfigManager configManager; private static Properties properties; //私有构造 private ConfigManager() { String configFile = "database.properties"; InputStream is = null; properties = new Properties(); try { is = ConfigManager.class.getClassLoader().getResourceAsStream(configFile); properties.load(is); is.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 静态内部类 */ public static class ConfigManagerHelper { private static final ConfigManager CONFIG_MANAGER = new ConfigManager(); } /** * 获取ConfigManager实例的方法 * * @return */ public static ConfigManager getInstance() { configManager = ConfigManagerHelper.CONFIG_MANAGER; return configManager; } public static String getProperty(String key) { return properties.getProperty(key); } }
3.3.8 BaseDao
package com.aiden.springmvc.cvs.dao; import com.aiden.springmvc.cvs.utils.ConfigManager; import java.sql.*; /** * 操作数据库的基类--静态类 * * @author Aiden */ public class BaseDao { private static BaseDao baseDao = new BaseDao(); /** * 私有化构造方法 */ private BaseDao() { getConnection(); } /** * 获取BaseDao实例对象 * * @return */ public static BaseDao getInstance() { return baseDao; } /** * 获取数据库连接对象 * * @return */ public static Connection getConnection() { Connection connection = null; String driver = ConfigManager.getInstance().getProperty("driver"); String url = ConfigManager.getInstance().getProperty("url"); String user = ConfigManager.getInstance().getProperty("user"); String password = ConfigManager.getInstance().getProperty("password"); try { Class.forName(driver);//加载驱动 connection = DriverManager.getConnection(url, user, password);//建立连接 } catch (Exception e) { e.printStackTrace(); } return connection; } /** * 查询操作 */ public static ResultSet execute(Connection connection, PreparedStatement stmt, ResultSet rs, String sql, Object... params) throws Exception { stmt = connection.prepareStatement(sql); for (int i = 0; i < params.length; i++) { stmt.setObject(i + 1, params[i]); } rs = stmt.executeQuery(); return rs; } /** * 更新操作 */ public static int execute(Connection connection, PreparedStatement stmt, String sql, Object... params) throws Exception { int updateRows = 0; stmt = connection.prepareStatement(sql); for (int i = 0; i < params.length; i++) { stmt.setObject(i + 1, params[i]); } updateRows = stmt.executeUpdate(); return updateRows; } /** * 释放资源 */ public static boolean closeResource(Connection connection, PreparedStatement stmt, ResultSet rs) { boolean flag = true; if (rs != null) { try { rs.close(); rs = null;//GC回收 } catch (SQLException e) { e.printStackTrace(); flag = false; } } if (stmt != null) { try { stmt.close(); stmt = null;//GC回收 } catch (SQLException e) { e.printStackTrace(); flag = false; } } if (connection != null) { try { connection.close(); connection = null;//GC回收 } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); flag = false; } } return flag; } }
3.3.9 SysUserDaoImpl
package com.aiden.springmvc.cvs.dao.impl; import com.aiden.springmvc.cvs.dao.BaseDao; import com.aiden.springmvc.cvs.dao.SysUserDao; import com.aiden.springmvc.cvs.pojo.SysUser; import org.springframework.stereotype.Repository; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; /** * dao层抛出异常,让service层去捕获处理 * * @author Aiden */ @Repository public class SysUserDaoImpl implements SysUserDao { @Override public int insert(Connection connection, SysUser sysUser) throws Exception { PreparedStatement stmt = null; int updateRows = 0; if (null != connection) { String sql = "insert into t_sys_user (account,realName,password," + "roleId,sex,birthday,phone,address,createTime,createUserId) " + "values(?,?,?,?,?,?,?,?,?,?)"; Object[] params = {sysUser.getAccount(), sysUser.getRealName(), sysUser.getPassword(), sysUser.getRoleId(), sysUser.getSex(), sysUser.getBirthday(), sysUser.getPhone(), sysUser.getAddress(), sysUser.getCreatedTime(), sysUser.getCreatedUserId()}; updateRows = BaseDao.execute(connection, stmt, sql, params); BaseDao.closeResource(null, stmt, null); } return updateRows; } @Override public SysUser findUserByAccount(Connection connection, String account) throws Exception { PreparedStatement pstm = null; ResultSet rs = null; SysUser user = null; if (null != connection) { String sql = "select * from t_sys_user where account=?"; Object[] params = {account}; rs = BaseDao.execute(connection, pstm, rs, sql, params); if (rs.next()) { user = new SysUser(); user.setId(rs.getInt("id")); user.setAccount(rs.getString("account")); user.setRealName(rs.getString("realName")); user.setPassword(rs.getString("password")); user.setSex(rs.getInt("sex")); user.setBirthday(rs.getDate("birthday")); user.setPhone(rs.getString("phone")); user.setAddress(rs.getString("address")); user.setRoleId(rs.getInt("roleId")); user.setCreatedUserId(rs.getInt("createdUserId")); user.setCreatedTime(rs.getTimestamp("createdTime")); user.setUpdatedUserId(rs.getInt("updatedUserId")); user.setUpdatedTime(rs.getTimestamp("updatedTime")); } BaseDao.closeResource(null, pstm, rs); } return user; } @Override public List<SysUser> findList(Connection connection, String realName, int userRoleId, int currentPageNo, int pageSize) throws Exception { PreparedStatement stmt = null; ResultSet rs = null; List<SysUser> userList = new ArrayList<SysUser>(); if (connection != null) { StringBuffer sql = new StringBuffer(); sql.append("select u.*,r.roleName as roleIdName from t_sys_user u,t_sys_role r where u.roleId = r.id"); List<Object> list = new ArrayList<Object>(); if (userRoleId > 0) { sql.append(" and u.roleId = ?"); list.add(userRoleId); } sql.append(" order by createdTime DESC limit ?,?"); currentPageNo = (currentPageNo - 1) * pageSize; list.add(currentPageNo); list.add(pageSize); Object[] params = list.toArray(); System.out.println("sql ----> " + sql.toString()); rs = BaseDao.execute(connection, stmt, rs, sql.toString(), params); while (rs.next()) { SysUser _user = new SysUser(); _user.setId(rs.getInt("id")); _user.setAccount(rs.getString("account")); _user.setRealName(rs.getString("realName")); _user.setSex(rs.getInt("sex")); _user.setBirthday(rs.getDate("birthday")); _user.setPhone(rs.getString("phone")); _user.setRoleId(rs.getInt("roleId")); _user.setRoleIdName(rs.getString("roleIdName")); userList.add(_user); } BaseDao.closeResource(null, stmt, rs); } return userList; } @Override public int getTotalCount(Connection connection, String realName, int userRoleId) throws Exception { PreparedStatement stmt = null; ResultSet rs = null; int count = 0; if (connection != null) { StringBuffer sql = new StringBuffer(); sql.append("select count(1) as count from t_sys_user u,t_sys_role r where u.roleId = r.id"); List<Object> list = new ArrayList<Object>(); if (userRoleId > 0) { sql.append(" and u.roleId = ?"); list.add(userRoleId); } Object[] params = list.toArray(); System.out.println("sql ----> " + sql.toString()); rs = BaseDao.execute(connection, stmt, rs, sql.toString(), params); if (rs.next()) { count = rs.getInt("count"); } BaseDao.closeResource(null, stmt, rs); } return count; } @Override public int deleteUserById(Connection connection, Integer id) throws Exception { PreparedStatement stmt = null; int updateRows = 0; if (null != connection) { String sql = "delete from t_sys_user where id=?"; Object[] params = {id}; updateRows = BaseDao.execute(connection, stmt, sql, params); BaseDao.closeResource(null, stmt, null); } return updateRows; } @Override public SysUser getUserById(Connection connection, String id) throws Exception { SysUser user = null; PreparedStatement stmt = null; ResultSet rs = null; if (null != connection) { String sql = "select u.*,r.roleName as roleIdName from t_sys_user u,t_sys_role r where u.id=? and u.roleId = r.id"; Object[] params = {id}; rs = BaseDao.execute(connection, stmt, rs, sql, params); if (rs.next()) { user = new SysUser(); user.setId(rs.getInt("id")); user.setAccount(rs.getString("account")); user.setRealName(rs.getString("realName")); user.setPassword(rs.getString("password")); user.setSex(rs.getInt("sex")); user.setBirthday(rs.getDate("birthday")); user.setPhone(rs.getString("phone")); user.setAddress(rs.getString("address")); user.setRoleId(rs.getInt("roleId")); user.setCreatedUserId(rs.getInt("createUserId")); user.setCreatedTime(rs.getTimestamp("createdTime")); user.setUpdatedUserId(rs.getInt("updatedUserId")); user.setUpdatedTime(rs.getTimestamp("updatedTime")); user.setRoleIdName(rs.getString("roleIdName")); } BaseDao.closeResource(null, stmt, rs); } return user; } @Override public int modify(Connection connection, SysUser user) throws Exception { int updateRows = 0; PreparedStatement pstm = null; if (null != connection) { String sql = "update t_sys_user set realName=?,sex=?,birthday=?,phone=?,address=?,roleId=?,updatedUserId=?,updatedTime=? where id = ? "; Object[] params = {user.getRealName(), user.getSex(), user.getBirthday(), user.getPhone(), user.getAddress(), user.getRoleId(), user.getUpdatedUserId(), user.getUpdatedTime(), user.getId()}; updateRows = BaseDao.execute(connection, pstm, sql, params); BaseDao.closeResource(null, pstm, null); } return updateRows; } @Override public int updatePwd(Connection connection, int id, String password) throws Exception { int updateRows = 0; PreparedStatement stmt = null; if (connection != null) { String sql = "update t_sys_user set password= ? where id = ?"; Object[] params = {password, id}; updateRows = BaseDao.execute(connection, stmt, sql, params); BaseDao.closeResource(null, stmt, null); } return updateRows; } }
3.3.10 SysUserService
package com.aiden.springmvc.cvs.service; import com.aiden.springmvc.cvs.pojo.SysUser; import java.util.List; /** * 业务接口 * * @author Aiden */ public interface SysUserService { /** * 增加用户信息 * * @param user * @return */ boolean addUser(SysUser user); /** * 用户登录 * * @param account 用户编码 * @param password 用户密码 * @return */ SysUser login(String account, String password); /** * 根据条件查询用户列表 * * @param queryUserName 用户姓名 * @param queryUserRoleId 角色编号 * @return */ List<SysUser> findUserList(String queryUserName, int queryUserRoleId, int currentPageNo, int pageSize); /** * 根据条件查询用户表记录数 * * @param queryUserName 用户姓名 * @param queryUserRoleId 角色编号 * @return */ int getUserCount(String queryUserName, int queryUserRoleId); /** * 根据用户编码查询用户是存在 * * @param account * @return */ SysUser findUserByAccount(String account); /** * 根据ID删除user * * @param delId 要删除的用户编号 * @return */ boolean deleteUserById(Integer delId); /** * 根据ID查找user * * @param id * @return */ SysUser findUserById(String id); /** * 修改用户信息 * * @param user * @return */ boolean modifyUser(SysUser user); /** * 根据userId修改密码 * * @param id 用户编号 * @param password 要修改的密码 * @return */ boolean updatePwd(int id, String password); }
3.3.11 SysUserServiceImpl
package com.aiden.springmvc.cvs.service.impl; import com.aiden.springmvc.cvs.dao.BaseDao; import com.aiden.springmvc.cvs.dao.SysUserDao; import com.aiden.springmvc.cvs.pojo.SysUser; import com.aiden.springmvc.cvs.service.SysUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.sql.Connection; import java.sql.SQLException; import java.util.List; /** * service业务层捕获异常,进行事务处理 * 事务处理:调用不同dao的多个方法,必须使用同一个connection(connection作为参数传递) * 事务完成之后,需要在service层进行connection的关闭,在dao层关闭(PreparedStatement和ResultSet对象) * * @author Aiden */ @Service public class SysUserServiceImpl implements SysUserService { @Resource private SysUserDao userDao; @Override public boolean addUser(SysUser user) { boolean flag = false; Connection connection = null; try { connection = BaseDao.getConnection(); connection.setAutoCommit(false);//开启JDBC事务管理 int updateRows = userDao.insert(connection, user); connection.commit();//提交事务 if (updateRows > 0) { flag = true; System.out.println("新增成功!"); } else { System.out.println("新增失败!"); } } catch (Exception e) { e.printStackTrace(); try { System.out.println("rollback 回滚事务"); connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { //在service层进行connection连接的关闭 BaseDao.closeResource(connection, null, null); } return flag; } @Override public SysUser login(String account, String password) { Connection connection = null; SysUser user = null; try { connection = BaseDao.getConnection(); user = userDao.findUserByAccount(connection, account); } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } //判断密码是否匹配 if (null != user) { if (!user.getPassword().equals(password)) { user = null; } } return user; } @Override public List<SysUser> findUserList(String queryUserName, int queryUserRoleId, int currentPageNo, int pageSize) { Connection connection = null; List<SysUser> userList = null; System.out.println("queryUserName ---- > " + queryUserName); System.out.println("queryUserRoleId ---- > " + queryUserRoleId); System.out.println("currentPageNo ---- > " + currentPageNo); System.out.println("pageSize ---- > " + pageSize); try { connection = BaseDao.getConnection(); userList = userDao.findList(connection, queryUserName, queryUserRoleId, currentPageNo, pageSize); } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return userList; } @Override public int getUserCount(String queryUserName, int queryUserRoleId) { Connection connection = null; int count = 0; System.out.println("queryUserName ---- > " + queryUserName); System.out.println("queryUserRoleId ---- > " + queryUserRoleId); try { connection = BaseDao.getConnection(); count = userDao.getTotalCount(connection, queryUserName, queryUserRoleId); } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return count; } @Override public SysUser findUserByAccount(String account) { Connection connection = null; SysUser user = null; try { connection = BaseDao.getConnection(); user = userDao.findUserByAccount(connection, account); } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return user; } @Override public boolean deleteUserById(Integer delId) { Connection connection = null; boolean flag = false; try { connection = BaseDao.getConnection(); if (userDao.deleteUserById(connection, delId) > 0) flag = true; } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return flag; } @Override public SysUser findUserById(String id) { SysUser user = null; Connection connection = null; try { connection = BaseDao.getConnection(); user = userDao.getUserById(connection, id); } catch (Exception e) { //记录异常日志.... e.printStackTrace(); user = null; } finally { BaseDao.closeResource(connection, null, null); } return user; } @Override public boolean modifyUser(SysUser user) { Connection connection = null; boolean flag = false; try { connection = BaseDao.getConnection(); if (userDao.modify(connection, user) > 0) flag = true; } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return flag; } @Override public boolean updatePwd(int id, String password) { boolean flag = false; Connection connection = null; try { connection = BaseDao.getConnection(); if (userDao.updatePwd(connection, id, password) > 0) { flag = true; } } catch (Exception e) { //记录异常日志.... e.printStackTrace(); } finally { BaseDao.closeResource(connection, null, null); } return flag; } }
3.3.12 SysUserController
package com.aiden.springmvc.cvs.controller; import com.aiden.springmvc.cvs.pojo.SysUser; import com.aiden.springmvc.cvs.service.SysUserService; import com.aiden.springmvc.cvs.utils.Constants; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller @RequestMapping("user") public class SysUserController { //日志 private Logger logger = Logger.getLogger(SysUserController.class); //用户业务实例对象 @Resource private SysUserService sysUserService; @RequestMapping("/hello") public String welcome(String realName) { logger.info("欢迎使用Spring MVC, realName:" + realName); return "index"; } //跳转到登录页面 @RequestMapping(value = "/toLogin") public String login() { logger.debug("跳转到登录页面"); return "login"; } //处理登录请求的方法 @RequestMapping(value = "/login", method = RequestMethod.POST) public String doLogin(@RequestParam String account, @RequestParam String password, HttpServletRequest request, HttpSession session) { logger.debug("登录方法"); //调用service方法,进行用户匹配 SysUser sysUser = sysUserService.login(account, password); if (null != sysUser) {//登录成功 //放入session session.setAttribute(Constants.USER_SESSION, sysUser); //重定向到/user/main.htme接口 return "redirect:/user/toMain"; } else { //页面跳转(login.jsp)带出提示信息--转发 request.setAttribute("error", "用户名或密码不正确"); return "login"; } } @RequestMapping(value = "/toMain") public String main(HttpSession session) { if (session.getAttribute(Constants.USER_SESSION) == null) { //重定向到登录页面接口 return "redirect:/user/toLogin"; } return "frame"; } @RequestMapping(value = "/logout") public String logout(HttpSession session) { //清除session session.removeAttribute(Constants.USER_SESSION); return "login"; } }
3.3.13 login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>系统登录 - 724便利店管理系统</title> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/statics/css/style.css"/> </head> <body class="login_bg"> <section class="loginBox"> <header class="loginHeader"> <h1>724便利店管理系统</h1> </header> <section class="loginCont"> <form class="loginForm" action="${pageContext.request.contextPath }/user/login" name="actionForm" id="actionForm" method="post"> <div class="info">${error }</div> <div class="inputbox"> <label for="account">账号:</label> <input type="text" class="input-text" id="account" name="account" placeholder="请输入账号" required/> </div> <div class="inputbox"> <label for="password">密码:</label> <input type="password" id="password" name="password" placeholder="请输入密码" required/> </div> <div class="subBtn"> <input type="submit" value="登录"/> <input type="reset" value="重置"/> </div> </form> </section> </section> </body> </html>
3.3.14 frame.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@include file="/WEB-INF/jsp/common/head.jsp"%> <div class="right"> <img class="wColck" src="${pageContext.request.contextPath }/statics/images/clock.jpg" alt=""/> <div class="wFont"> <h2>${userSession.realName }</h2> <p>欢迎来到724便利店管理系统!</p> </div> </div> </section> <%@include file="/WEB-INF/jsp/common/foot.jsp" %>
3.3.15 common/head.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>724便利店管理系统</title> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/statics/css/style.css" /> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/statics/css/public.css" /> </head> <body> <!--头部--> <header class="publicHeader"> <h1>724便利店管理系统</h1> <div class="publicHeaderR"> <p><span style="color: #fff21b"> ${userSession.realName }</span> , 欢迎光临!</p> <a href="${pageContext.request.contextPath }/user/logout">登出</a> </div> </header> <!--时间--> <section class="publicTime"> <span id="time">2019年1月1日 11:11 星期一</span> <a href="#">为了保证正常使用,请使用IE10.0以上版本!</a> </section> <!--主体内容--> <section class="publicMian"> <div class="left"> <h2 class="leftH2"><span class="span1"></span>菜单 <span></span></h2> <nav> <ul class="list"> <li ><a href="${pageContext.request.contextPath }/jsp/storageRecord.do?method=query">入库记录信息</a></li> <li><a href="${pageContext.request.contextPath }/jsp/supplier.do?method=query">供货商信息</a></li> <li><a href="${pageContext.request.contextPath }/jsp/user.do?method=query">用户信息</a></li> <li><a href="${pageContext.request.contextPath }/jsp/sysUser/updatePassword.jsp">修改密码</a></li> <li><a href="${pageContext.request.contextPath }/user/logout">退出系统</a></li> </ul> </nav> </div> <input type="hidden" id="path" name="path" value="${pageContext.request.contextPath }"/> <input type="hidden" id="referer" name="referer" value="<%=request.getHeader("Referer")%>"/> <!-- </section> -->
3.3.16 common/foot.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div class="div_footer">
<footer class="footer" style="height: 30px">
版权归Aiden所有
</footer>
</div>
<script type="text/javascript" src="${pageContext.request.contextPath }/statics/js/time.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/statics/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/statics/js/common.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/statics/calendar/WdatePicker.js"></script>
</body>
</html>
3.3.17 maven pom.xml配置
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.19</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 添加JSTL标准标签库的Maven依赖-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
3.3.18 Constants 系统静态常量
package com.aiden.springmvc.cvs.utils;
/**
* @author Aiden
*/
public interface Constants {
/**
* 用户Session Key
*/
String USER_SESSION = "userSession";
/**
* 系统信息
*/
String SYS_MESSAGE = "message";
/**
* 分页时每页显示的行数
*/
int pageSize = 5;
}
四、静态资源文件的引用
4.1静态资源无法正常加载的原因
- 为什么页面中没有相应的样式和图片?
分析:
- web.xml中配置的DispatcherServlet请求映射为 “/”
- 怎么解决?
方案:
<mvc:resources/>
标签
- mapping:将静态资源映射到指定的路径下
- location:本地静态资源文件所在的目录
<mvc:resources mapping="/statics/**" location="/statics/" />
访问测试:
4.2登录功能优化
需求说明
1、登录成功后的当前用户信息需要保存在session中
2、如果登录失败,除了页面跳转到登录页,还需在页面上进行错误提示Servlet API对象作为处理方法的入参
HttpSession
HttpServletRequest页面上使用EL表达式显示相应信息
练习操作—改造724系统的登录、注销功能
需求说明
- 搭建SpringMVC+Spring+JDBC框架,并使用新的框架实现724系统的用户登录注销功能
- 将Spring配置文件进行拆分管理
- 用户登录成功后,将用户信息存储到session中并跳转到系统首页
- 退出登录时销毁session并跳转到登录页面
- 如果登录失败,须在登录页显示失败原因
五、异常处理
5.1异常处理
异常处理
- HandlerExceptionResolver
resolveException()
局部异常处理
- 仅能处理指定Controller中的异常
@ExceptionHandler
@Controller @RequestMapping("/user") public class SysUserController { private Logger logger = Logger.getLogger(SysUserController.class); /** * 一个抛出异常的接口 * @param account * @param password * @return */ @RequestMapping("/exLogin") public String exLogin(String account, String password){ logger.debug("一个抛出异常的接口"); //调用service方法,进行用户匹配 SysUser user = sysUserService.login(account,password); if(null == user){//登录失败 throw new NullPointerException("空指针异常!"); }else{ throw new RuntimeException("用户名或者密码不正确,跳转到错误页面!"); } //return "redirect:/user/toMain"; } /** * 捕获异常信息,跳转到error页面 */ @ExceptionHandler(value={Exception.class}) public String handlerException(Exception e, HttpServletRequest req){ req.setAttribute("e", e); return "error"; } }
- 视图页面 error.jsp
<body> <h1> ${e.message } </h1> </body>
5.2异常处理
- 全局异常处理
- 对所有异常进行统一处理
- 配置 SimpleMappingExceptionResolver ,发生异常时使用对应的视图error报告异常
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionAttribute" value="ex"></property> <property name="exceptionMappings"> <props> <prop key="java.lang.Exception">error</prop> </props> </property> </bean>
- 视图页面 error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>错误信息页面</title> </head> <body> <h6>异常信息:<span style="color: red">${requestScope.ex}</span></h6> </body> </html>
六、改造用户列表查询功能
6.1需求说明
- 原有业务不变,实现技术引入Spring和Spring MVC框架
- 改造用户管理功能模块中的用户列表查询功能
- 查询条件
- 用户名称(模糊匹配)、用户角色(精确匹配)
- 列表页显示字段
- 用户名、真实姓名、角色名称、年龄、电话等
- 分页显示数据列表
6.2实现步骤
- 改造Controller
SysUserController
中增加查询用户列表getUserList()
方法- 增加异常处理
- 增加处理异常请求的接口
/user/toSysError
- 改造View层
list.jsp
rollpage.jsp
- 增加sysError.jsp页面
6.3 练习—改造供货商列表查询功能
需求说明
- 在前面学员操作的基础上,实现供货商列表查询功能
- 要求可根据供货商编码、供货商名称进行模糊匹配并包含分页功能
七、本章总结
7.1本章总结
八、监听器
8.1 ContextLoaderListener监听器作用
ContextLoaderListener是一个监听器,由Spring编写并提供。
ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
配合ContextLoaderListener一起使用的,经常是context-param,用来指定Spring要加载的配置文件,比如:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Aiden Create Spring Web MVC</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param> <servlet> <servlet-name>spring-mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>spring-mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成