JavaWeb书城项目(十)——Filter过滤器和Aajx请求

前九个部分我们大致完成了书城项目的所有功能,第十部分我们做一个结尾,主要包括使用Filter过滤器进行权限检查,使用Filter和ThreadLocal组合管理事务,将异常同一交给Tomcat并展示友好的错误页面,使用Aajx请求改进功能。

Filter过滤器实现权限检查

我们要使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查。

  1. Filter的工作流程如下
    Filter工作流程图

  2. Filter 过滤器的使用步骤:

	1、 编写一个类去实现 Filter 接口
	
	2、 实现过滤方法 doFilter()
	
	3、 到 web.xml 中去配置 Filter
  1. Filter 的生命周期
	Filter 的生命周期包含几个方法
	1、构造器方法
	2、init 初始化方法
	第 12 步,在 web 工程启动的时候执行(Filter 已经创建)
	3、doFilter 过滤方法
	第 3 步,每次拦截到请求,就会执行
	4、destroy 销毁
	第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)
  1. Filter 的拦截路径
	--精确匹配
	<url-pattern>/target.jsp</url-pattern>
	以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp 

	--目录匹配
	<url-pattern>/admin/*</url-pattern>
	以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/* 

	--后缀名匹配
	<url-pattern>*.html</url-pattern>
	以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
	<url-pattern>*.do</url-pattern>
	以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
	<url-pattern>*.action</url-pattern>
	以上配置的路径,表示请求地址必须以.action 结尾才会拦截
  1. 创建ManagerFilter实现类
public class ManagerFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        Object user = httpServletRequest.getSession().getAttribute("user");

        if (user == null) {
            httpServletRequest.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

  1. 配置 web.xml 文件
    <filter>
        <filter-name>ManagerFilter</filter-name>
        <filter-class>com.atguigu.filter.ManagerFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ManagerFilter</filter-name>
        <url-pattern>/pages/manager/*</url-pattern>
        <url-pattern>/manager/bookServlet</url-pattern>
    </filter-mapping>

Filter和ThreadLocal组合管理事务

  1. ThreadLocal的作用
	ThreadLocal 的作用,它可以解决多线程的数据安全问题。
	
	ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
	
	ThreadLocal 的特点:
	1ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
	2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用	多个
	ThreadLocal 对象实例。
	3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
	4ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放
  1. 使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成。
    原理分析图
    JdbcUtils工具类的修改
public class JdbcUtils {

    private static DruidDataSource dataSource;
    private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>();

    static {
        try {
            Properties properties = new Properties();
            // 读取jdbc.properties文件
            InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            // 从流中加载数据
            properties.load(inputStream);
            // 创建数据库连接池
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }



    /**
     * 获取数据库连接池中的连接
     * @return 如果返回null,说明获取连接失败 <br/>有值就是成功
     */
    public static Connection getConnection(){

        Connection conn = conns.get();

        if (conn == null) {
            try {
                conn = dataSource.getConnection(); // 从数据库连接池中获取连接
                conns.set(conn); // 保存到ThreadLocal对象中,供后面的jdbc操作使用
                conn.setAutoCommit(false); // 设置为手动提交
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return conn;
    }

    /**
     * 提交事务,并关闭释放连接
     */
    public static void commitAndClose() {
        Connection connection = conns.get();
        if (connection != null) { // 如果不等于null,说明之前使用过连接,操作过数据库
            try {
                connection.commit(); // 提交事务
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        // 一定要执行remove操作,否则就会出错(因为Tomcat服务器底层使用了线程池技术)
        conns.remove();
    }

    public static void rollbackAndClose(){
        Connection connection = conns.get();
        if (connection != null) { //如果不等于null,说明之前使用过连接,操作过数据库
            try {
                connection.rollback(); // 回滚事务
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                try {
                    connection.close(); //关闭连接释放资源
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        // 一定要执行remove操作,否则就会出错(因为Tomcat底层使用了线程池技术)
        conns.remove();
    }
//
//    /**
//     * 关闭连接,放回数据库连接池
//     * @param conn
//     */
//    public static void close(Connection conn){
//        if(conn != null)
//        {
//            try {
//                conn.close();
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }
}

修改BaseDao

public abstract class BaseDao {

    // 使用DbUtils操作数据库
    private QueryRunner queryRunner = new QueryRunner();

    /**
     * update() 方法用来执行:Insert\Update\Delete语句
     * @return 如果返回-1说明执行失败<br/>返回其它表示影响的行数
     */
    public int update(String sql, Object ... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            return  queryRunner.update(connection, sql, args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询返回一个javaBean的sql语句
     * @param type 返回的对象类型
     * @param sql 执行的sql语句
     * @param args sql对应的参数值
     * @param <T> 返回的类型的泛型
     * @return
     */
    public <T> T queryForOne(Class<T> type, String sql, Object ... args){
        Connection con = JdbcUtils.getConnection();
        try {
            return queryRunner.query(con, sql, new BeanHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询返回多个javaBean的sql语句
     * @param type 返回的对象类型
     * @param sql 执行的sql语句
     * @param args sql对应的参数值
     * @param <T> 返回的类型的泛型
     * @return
     */
    public <T> List<T> queryForList(Class<T> type, String sql, Object ... args){
        Connection con = JdbcUtils.getConnection();
        try {
            return queryRunner.query(con, sql, new BeanListHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行返回一行一列的sql语句
     * @param sql 执行的sql语句
     * @param args sql对应的参数值
     * @return
     */
    public Object queryForSingleValue(String sql, Object ... args){

        Connection conn = JdbcUtils.getConnection();

        try  {
            return queryRunner.query(conn, sql, new ScalarHandler(), args);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
  1. 使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch。来进行实现的管理。
    原理分析图
    Filter类代码
public class TransactionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try{
            filterChain.doFilter(servletRequest, servletResponse);
            JdbcUtils.commitAndClose(); // 提交事务
        } catch (Exception e) {
            JdbcUtils.rollbackAndClose(); // 回滚事务
            e.printStackTrace();
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

配置web.xml

    <filter>
        <filter-name>TransactionFilter</filter-name>
        <filter-class>com.atguigu.filter.TransactionFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>TransactionFilter</filter-name>
        <!-- /* 表示当前工程下所有请求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

一定要记得把BaseServlet中的异常往外抛给Filter过滤器

public abstract class BaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 解决post请求中文乱码问题
        // 一定要在获取请求参数之前调用才有效
        req.setCharacterEncoding("UTF-8");

        String action = req.getParameter("action");

        try {
            // 获取action业务鉴别字符串,获得相应的业务 方法反射对象
            Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
            // 调用目标业务 方法
            method.invoke(this, req, resp);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e); // 把异常抛给Filter过滤器
        }

    }

}

Tomcat管理异常

我们将所有异常都统一交给 Tomcat,让Tomcat展示友好的错误信息页面,这样用户就不用面对一大堆问题代码了。

  1. web.xml中我们可以通过错误页面配置来进行管理
    <!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
    <error-page>
        <!--error-code 是错误类型-->
        <error-code>500</error-code>
        <!--location 标签表示。要跳转去的页面路径-->
        <location>/pages/error/error500.jsp</location>
    </error-page>
    <!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
    <error-page>
        <!--error-code 是错误类型-->
        <error-code>404</error-code>
        <!--location 标签表示。要跳转去的页面路径-->
        <location>/pages/error/error404.jsp</location>
    </error-page>
  1. 编写错误页面,我们就简单做一下
    error500.jsp
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
	<head>
	    <title>服务器出错啦</title>
	    <%-- 静态包含 base标签,css样式,jQuery文件 --%>
    	<%@ include file="/pages/common/head.jsp"%>
	</head>
	<body>
	服务器出错啦,程序员小哥正在加紧抢修。<br/>
	<a href="index.jsp">返回首页</a>
	</body>
	</html>

error404.jsp

	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
	<head>
	    <title>访问资源不存在</title>
	    <%-- 静态包含 base标签,css样式,jQuery文件 --%>
    	<%@ include file="/pages/common/head.jsp"%>
	</head>
	<body>
	您访问的资源不存在,或已被删除<br/>
	<a href="index.jsp">返回首页</a>
	</body>
	</html>
  1. TransactionFilter要把异常抛给Tomcat
    修改TransactionFilter

使用AJAX验证用户名是否可用

  1. 图解验证用户名是否可用流程
    验证用户名是否可用流程
  2. 导入相关jar
	gson-2.2.4.jar
  1. UserServlet程序添加ajaxExistsUsername方法
   /**
     * ajax请求判断用户名是否存在
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void ajaxExistUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求的参数username
        String username = req.getParameter("username");
        // 调用userService.existUsername()
        boolean existsUsername = userService.existsUsername(username);
        // 把返回的结果封装为map对象
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("existsUsername", existsUsername);

        Gson gson= new Gson();
        String json = gson.toJson(resultMap);

        resp.getWriter().write(json);
    }
  1. 修改regist.jsp中的代码
				// 给用户名绑定失去焦点事件
			$("#username").blur(function () {
				// 1. 获取用户名
				var username = this.value;
				//2 创建正则表达式对象
				var usernamePatt = /^\w{5,12}$/;
				//3 使用test方法验证
				if(!usernamePatt.test(username)) { // 用户名不合法
					//4 提示用户结果
					$("span.errorMsg").text("用户名不合法!");
				} else{
					// 用户名合法判断用户名是否存在
					// alert("用户名合法");
					$.getJSON("${pageScope.basePath}userServlet","action=ajaxExistsUsername&username=" + username,
							function (data) {
								if(data.existsUsername) { // 用户名存在
									$("span.errorMsg").text("用户名已存在!");
								} else { // 用户名可用
									$("span.errorMsg").text("用户名可用!");
								}
							});
				}
			});

AJAX添加商品到购物车

我们之前把商品添加到购物车,是刷新了整个页面,这样用户体验不是很好,我们可用使用Ajax请求来完成局部的更新。

  1. 图解商品加入购物车
    加入购物车流程

  2. CartServlet程序添加ajaxAddItem方法

    protected void ajaxAddItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求的参数 商品编号
        int id = WebUtils.parseInt(req.getParameter("id"), 0);
        // 调用 bookService.queryBookById(id):Book 得到图书的信息
        Book book = bookService.queryBookById(id);
        // 把图书信息,转换为CartItem商品项
        CartItem cartItem = new CartItem(book.getId(), book.getName(), 1, book.getPrice(), book.getPrice());
        // 调用Cart.addItem(CartItem);添加商品项
        Cart cart = (Cart) req.getSession().getAttribute("cart");
        if (cart == null) {
            cart = new Cart();
            req.getSession().setAttribute("cart", cart);
        }
        cart.addItem(cartItem);
        System.out.println(cart);

        // 最后一个添加的商品名称
        req.getSession().setAttribute("lastName", cartItem.getName());

        // 返回购物车总的商品数量和最后一个添加的商品名称
        Map<String, Object> resultMap = new HashMap<String, Object>();

        resultMap.put("totalCount", cart.getTotalCount());
        resultMap.put("lastName", cartItem.getName());

        Gson gson = new Gson();
        String resultMapJsonString = gson.toJson(resultMap);

        resp.getWriter().write(resultMapJsonString);
    }
  1. 修改index.jsp页面

html代码

js代码

  1. 修改BaseServlet程序解决中文乱码问题
    解决中文乱码问题
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JavaWeb书城项目是一个基于JavaWeb技术开发的在线图书销售平台。该项目旨在为用户提供一个方便快捷的购书平台,并支持在线购买、浏览图书信息等功能。 该项目的主要功能包括用户注册登录、图书分浏览、商品搜索、购物车管理、订单管理等。 用户可以通过注册登录功能创建自己的账号,并进行个人信息的管理。用户登录后可以浏览不同分的图书,并支持按关键字搜索特定的图书。同时,用户可以将心仪的图书添加到购物车,并支持修改购物车数量和删除购物车的图书。当用户完成商品的选购后,可以提交订单进行结算,实现购物流程的完整。 图书分浏览的功能可以让用户根据自己的需求,选择不同的图书分进行浏览和选择。用户可以根据自己的兴趣和需求来选择特定型的图书。 商品搜索功能可以方便用户根据关键字快速找到所需要的图书。用户只需输入关键字即可快速搜索到与该关键字相关的图书信息。 购物车管理功能可以帮助用户管理已选购的图书。用户可以对购物车的图书进行数量的增减和删除操作,方便用户根据自己的需求进行调整。 订单管理功能可以帮助用户查看和管理自己的订单。用户可以查看已购买的订单详情,并支持订单的取消和重新购买等操作。 总之,该JavaWeb书城项目通过提供用户注册登录、图书分浏览、商品搜索、购物车管理、订单管理等功能,为用户打造了一个便利的在线图书销售平台。用户可以通过该平台方便地浏览、购买自己喜欢的图书,提高图书销售的便捷性和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值