1.练习
图书条件查询:创建图书表,编号,书名,作者,价格,出版日期;
要求:可以按照书名和作者进行模糊查询。
关键代码:
数据访问dao:
public class BookDaoImpl implements IBookDao {
@Override
public List<Book> selectAllBook() {
String sql = "select * from Book";
BaseDao.setPst(sql,null);
List<Map<String,Object>> rows = BaseDao.executeQuery();
List<Book> books = new ArrayList<>();
if(rows.size()>0){
for (Map map: rows) {
Book book = new Book(
(Integer) map.get("id"),
(String) map.get("name"),
(String) map.get("author"),
new BigDecimal(map.get("price").toString()).doubleValue(),
(Date)map.get("prcDate")
);
books.add(book);
}
}
return books;
}
@Override
public List<Book> selectSomeBook(String[] conditions,int n) {
String sql = "select * from book";
List<Object> params = new ArrayList<>();
for (String s:conditions) {
params.add("%"+s+"%");
}
switch (n){
case 1:
sql = "select * from book where name like ?";
break;
case 2:
sql = "select * from book where author like ?";
break;
case 3:
sql = "select * from book where name like ? and author like ?";
break;
default:
break;
}
BaseDao.setPst(sql, params.toArray());
List<Map<String,Object>> rows = BaseDao.executeQuery();
List<Book> books = new ArrayList<>();
if(rows.size()>0){
for (Map map: rows) {
Book book = new Book(
(Integer) map.get("id"),
(String) map.get("name"),
(String) map.get("author"),
new BigDecimal(map.get("price").toString()).doubleValue(),
(Date)map.get("prcDate")
);
books.add(book);
}
return books;
}
return null;
}
}
servlet:
@WebServlet(urlPatterns = "/BookServlet/*")
public class BookServlet extends HttpServlet {
IBookService bookService = new BookServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;character=UTF-8");
String uri = req.getRequestURI();
String operation = uri.substring(uri.lastIndexOf("/")+1);
switch (operation){
case "select":
this.selectBook(req,resp);
break;
case "selectSome":
this.selectSome(req,resp);
break;
default:
break;
}
}
private void selectSome(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String condition_name = req.getParameter("condition_name");
String condition_author = req.getParameter("condition_author");
req.setAttribute("condition_name",condition_name);
req.setAttribute("condition_author",condition_author);
if(StringUtils.isNullOrEmpty(condition_name)&&StringUtils.isNullOrEmpty(condition_author)){
this.selectBook(req,resp);
}
if(!StringUtils.isNullOrEmpty(condition_name)&&!StringUtils.isNullOrEmpty(condition_author)){
req.setAttribute("books",bookService.selectSomeBook(new String[]{condition_name,condition_author},3));
}else {
if(!StringUtils.isNullOrEmpty(condition_name)){
req.setAttribute("books_name",bookService.selectSomeBook(new String[]{condition_name},1));
}
if(!StringUtils.isNullOrEmpty(condition_author)){
req.setAttribute("books_author",bookService.selectSomeBook(new String[]{condition_author},2));
}
}
req.getRequestDispatcher("/main.jsp").forward(req,resp);
}
private void selectBook(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("books",bookService.selectAllBook());
req.getRequestDispatcher("/main.jsp").forward(req,resp);
}
}
2.数据库连接池
2.1 介绍
数据库连接池负责分配,管理和释放数据库连接,允许程序重复的使用现有的数据库连接,而不是重新建立(JDBC则是在我们每次操作数据库的时候,创建一个连接,使用过就关闭);释放空闲事件超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏;能够明显提高对数据库操作的性能。
2.2 常见的数据库连接池
C3P0,Proxool,Jakarta DBCP,DBPool,Druid(德鲁伊特)
2.3 使用连接池
2.3.1 导入jar包,并添加db.properties
db.properties:
#驱动加载
driverClassName=com.mysql.cj.jdbc.Driver
#注册驱动
url=jdbc:mysql://127.0.0.1:3306/test_0803?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
#连接数据库的用户名
username=root
#连接数据库的密码
password=123456
#属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wall
filters=stat
#初始化时池中建立的物理连接个数。
initialSize=5
#最大的可活跃的连接池数量
maxActive=300
#获取连接时最大等待时间,单位毫秒,超过连接就会失效。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
maxWait=60000
#连接回收器的运行周期时间,时间到了清理池中空闲的连接,testWhileIdle根据这个判断
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
#建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。
testWhileIdle=true
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。设置为false
testOnBorrow=false
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能,设置为false
testOnReturn=false
#是否缓存preparedStatement,也就是PSCache。
poolPreparedStatements=false
#池中能够缓冲的preparedStatements语句数量
maxPoolPreparedStatementPerConnectionSize=200
2.3.2 修改原来的BaseDao文件
//定义连接池数据源对象
private static DataSource dataSource;
//静态代码块
static {
try {
//getClassLoader():获取类的加载器
//getResourceAsStream():通过类加载器,获取指定文件的输入流对象
InputStream is = BaseDAO.class.getClassLoader().getResourceAsStream("/db.properties");
//使用Properis对象,加载properties文件
Properties properties = new Properties();
//使用properties文件,加载配置数据
properties.load(is);
//创建druid连接池数据源,用配置文件做参数
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception exception) {
exception.printStackTrace();
}
}
//获取连接
public static Connection getConnection(){
Connection con = null;
try{
//加载驱动类
//Class.forName(DRIVER);
//获取连接
//con = DriverManager.getConnection(URL,USER,PASSWORD);
//从连接池数据源中获取连接对象
con = dataSource.getConnection();
}catch(Exception ex){
ex.printStackTrace();
}
return con;
}
3. 过滤器
3.1 作用
Java过滤器可以对目标资源的请求和响应进行过滤/拦截,一般用于通过的操作;如:登录过滤,编码处理,敏感字符过滤等。
3.2 使用
实现接口Filter,重写方法:
① chain,doFilter(req,resp)放行方法;
② 配置访问拦截的路径。
@WebFilter(urlPatterns = "/*")
public class CharacterEncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//设置编码
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;character=utf-8");
//请求放行
filterChain.doFilter(servletRequest,servletResponse);
}
}
web.xml 配置:
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.wen.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<!-- * : 过滤当前项目的所有请求 -->
<url-pattern>/*</url-pattern>
<!-- 过滤方式的配置(资源被访问的方式) -->
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
过滤路径配置:
①具体的资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行;
②拦截目录:/user/* 访问user目录下的所有资源时,过滤器会被执行;
③后缀名拦截:*.jsp / *.do 访问所有后缀名为.jsp .do时,过滤器会被执行;
④拦截所有资源: /* 访问所有资源时,过滤器都会被执行。
设置dispatcherTypes属性:
①REQUEST:默认值 浏览器直接请求资源;
②FORWARD:转发访问资源;
③INCLUDE:包含访问资源;
④ERROR:错误跳转资源;
⑤ASYNC:异步访问资源。
3.3 过滤器的执行流程
客户端请求---->过滤器---->放行---->请求的资源---->响应---->过滤器---->客户端
过滤器链的执行顺序:
过滤器1--->过滤器2--->资源执行--->过滤器2--->过滤器1
过滤器的顺序:
①注解配置:按照类名的字符串比较规则比较,小的先执行;
②web.xml配置:<filter-mapping>在上边的先执行。
3.4 实现登录功能的过滤(白名单)
//@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {
private String[] whiteNames;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String params = filterConfig.getInitParameter("whiteNames");
whiteNames = params.split(",");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String uri = req.getRequestURI();
String operation = uri.substring(uri.lastIndexOf("/")+1);
System.out.println("请求地址"+operation);
boolean isWhiteName = false;
for (String s:whiteNames) {
System.out.println("白名单:"+s);
if(operation.equals(s)){
isWhiteName=true;
break;
}
}
if(isWhiteName){
filterChain.doFilter(servletRequest, servletResponse);
}else {
if(req.getSession().getAttribute("userName")==null){
req.getRequestDispatcher("/ToLoginServlet").forward(req,resp);
}else {
req.getRequestDispatcher("/ToMainServlet").forward(req,resp);
}
}
}
}
4. 监听器
4.1 用途
监听web应用,其信息的初始化,销毁,增加,修改,删除值;servlet监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。
4.2 分类
在一个web应用程序的整个运行周期内,web容器会创建和销毁三个重要的对象:ServletContext,HttpSession,ServletRequest。
按监听的对象划分,可以分为:
ServletContext对象监听器;HttpSession对象监听器,ServletRequest对象监听器
按监听事件分:
①对象自身的创建和销毁的监听器;
②对象中属性的创建和消除的监听器;
③session中某个对象的状态变化的监听器。
4.3 创建监听器
4.3.1 监听器的注册
①添加注解的方式:
@WebListener
②web.xml 配置
<listener>
<listener-class>com.wen.listener.ContextListener</listener-class>
</listener>
4.3.2 上下文监听器
//@WebListener
public class ContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext application = sce.getServletContext();
System.out.println("上下文初始化/网站初始化:"+application);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("上下文销毁/网站销毁!");
}
}
jsp中的application域对象与servlet中的ServletContext是一样的,jsp的编译过程:ServletContext application = pageContext.getServletContext()。
4.3.3 session监听
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session创建了:"+se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session销毁了:"+se.getSession().getId());
}
}
4.3.4 session 属性的监听
@WebListener
public class SessionAttributeListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("属性添加:"+se.getName()+" "+se.getValue());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("属性删除:"+se.getName()+" "+se.getValue());
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("属性改变:"+se.getName()+" "+se.getValue());
}
}
4.3.5 ServletRequest 监听
@WebListener
public class ServletRequest implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("销毁!");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("创建!");
}
}
4.4 在线人数的统计
@WebListener
public class OnlineListener implements ServletContextListener, HttpSessionListener {
private ServletContext application;
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("网页初始化!");
application = sce.getServletContext();
if(application.getAttribute("count")==null){
application.setAttribute("count",0);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("人数++");
Integer count = (Integer) application.getAttribute("count");
count++;
System.out.println("count:"+count);
application.setAttribute("count",count);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("人数--");
Integer count = (Integer) application.getAttribute("count");
count--;
application.setAttribute("count",count);
}
}