【后端】Maven 体系(五)

Maven 体系

3. 搭建环境:事务控制

3.1 总体思路

【后端】Maven 体系(五)_第1张图片

3.2 TransactionFilter

3.2.1 创建 Filter 类

【后端】Maven 体系(五)_第2张图片

3.2.2 TransactionFilter 完整代码
public class TransactionFilter implements Filter {

    // 声明集合保存静态资源扩展名
    private static Set<String> staticResourceExtNameSet;

    static {
        staticResourceExtNameSet = new HashSet<>();
        staticResourceExtNameSet.add(".png");
        staticResourceExtNameSet.add(".jpg");
        staticResourceExtNameSet.add(".css");
        staticResourceExtNameSet.add(".js");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        // 前置操作:排除静态资源
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String servletPath = request.getServletPath();
        if (servletPath.contains(".")) {
            String extName = servletPath.substring(servletPath.lastIndexOf("."));

            if (staticResourceExtNameSet.contains(extName)) {

                // 如果检测到当前请求确实是静态资源,则直接放行,不做事务操作
                filterChain.doFilter(servletRequest, servletResponse);

                // 当前方法立即返回
                return ;
            }

        }

        Connection connection = null;

        try{

            // 1、获取数据库连接
            connection = JDBCUtils.getConnection();

            // 重要操作:关闭自动提交功能
            connection.setAutoCommit(false);

            // 2、核心操作
            filterChain.doFilter(servletRequest, servletResponse);

            // 3、提交事务
            connection.commit();

        }catch (Exception e) {

            try {
                // 4、回滚事务
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }

            // 页面显示:将这里捕获到的异常发送到指定页面显示
            // 获取异常信息
            String message = e.getMessage();

            // 将异常信息存入请求域
            request.setAttribute("systemMessage", message);

            // 将请求转发到指定页面
            request.getRequestDispatcher("/").forward(request, servletResponse);

        }finally {

            // 5、释放数据库连接
            JDBCUtils.releaseConnection(connection);

        }

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
    @Override
    public void destroy() {}
}
3.2.3 配置 web.xml
  • 注意:需要首先将当前工程改成 Web 工程。
    【后端】Maven 体系(五)_第3张图片
<filter>
    <filter-name>txFilterfilter-name>
    <filter-class>com.alex.imperial.court.filter.TransactionFilterfilter-class>
filter>
<filter-mapping>
    <filter-name>txFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>
3.2.4 注意点
  • 确保异常回滚

    • 在程序执行的过程中,必须让所有 catch 块都把编译时异常转换为运行时异常抛出;如果不这么做,在 TransactionFilter 中 catch 就无法捕获到底层抛出的异常,那么该回滚的时候就无法回滚。
  • 谨防数据库连接提前释放

    • 由于诸多操作都是在使用同一个数据库连接,那么中间任何一个环节释放数据库连接都会导致后续操作无法正常完成。

4. 搭建环境:表述层

4.1 视图模板技术 Thymeleaf

4.1.1 服务器端渲染

【后端】Maven 体系(五)_第4张图片

4.1.2 拓展:后端工程师与前端工程师交互
  • 服务器端渲染
    • 除了我们熟悉的JSP,还有Velocity、Freemarker、Thymeleaf等视图模板技术。虽然具体语法各不相同,但是它们都有一个共通的特点,就是在固定内容中可以穿插表达式等形式的动态内容。将视图模板中的动态内容转换为对应的Java代码并执行,然后使用计算得到的具体数据替换原来的动态部分。这样整个文件的动态内容就可以作为确定的响应结果返回给浏览器。在这种模式下,前端工程师将前端页面全部开发完成,交给后端程序员加入到项目中。此时不可避免的需要后端程序员根据需要对前端代码进行补充和调整。
      【后端】Maven 体系(五)_第5张图片
  • 前后端分离
    • 前后端分离模式下,前端程序和后端程序使用JSON格式进行交互,所以项目启动时前端工程和后端工程师需要坐在一起开会,商量确定JSON格式的具体细节。然后分头开发。后端工程师在把后端的代码发布到测试服务器前,前端工程师无法调用后端程序拿到真实数据,所以使用Mock.js生成假数据。直到后端工程师开发完成,后端程序发布到了测试服务器上,前端工程师再从Mock.js切换到实际后端代码。
      【后端】Maven 体系(五)_第6张图片
4.1.3 Thymeleaf 简要工作机制
4.1.3.1 初始化阶段
  • 目标:创建 TemplateEngine 对象
  • 封装:因为对每一个请求来说,TemplateEngine 对象使用的都是同一个,所以在初始化阶段准备好
    【后端】Maven 体系(五)_第7张图片
4.1.3.2 请求处理阶段

【后端】Maven 体系(五)_第8张图片

4.1.4 逻辑视图与物理视图

假设有下列页面地址:

/WEB-INF/pages/apple.html
/WEB-INF/pages/banana.html
/WEB-INF/pages/orange.html
/WEB-INF/pages/grape.html
/WEB-INF/pages/egg.html
  • 这样的地址可以直接访问到页面本身,我们称之为:物理视图。而将物理视图中前面、后面的固定内容抽取出来,让每次请求指定中间变化部分即可,那么中间变化部分就叫:逻辑视图
    【后端】Maven 体系(五)_第9张图片
4.1.5 ViewBaseServlet 完整代码
public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}
  • 特别提醒:这个类不需要掌握,因为以后都被框架封装了,我们现在只是暂时用一下。
    【后端】Maven 体系(五)_第10张图片
4.1.6 声明初始化参数

【后端】Maven 体系(五)_第11张图片



<context-param>
    <param-name>view-prefixparam-name>
    <param-value>/WEB-INF/pages/param-value>
context-param>
<context-param>
    <param-name>view-suffixparam-name>
    <param-value>.htmlparam-value>
context-param>

4.2 ModelBaseServlet

4.2.1 提出问题
4.2.1.1 我们的需求

【后端】Maven 体系(五)_第12张图片

4.2.1.2 HttpServlet 的局限
  • doGet() 方法:处理 GET 请求
  • doPost() 方法:处理 POST 请求
4.2.2 解决方案
  • 每个请求附带一个请求参数,表明自己要调用的目标方法
  • Servlet 根据目标方法名通过反射调用目标方法
4.2.3 ModelBaseServlet 完整代码

【后端】Maven 体系(五)_第13张图片

  • 特别提醒:为了配合 TransactionFilter 实现事务控制,捕获的异常必须抛出。
public class ModelBaseServlet extends ViewBaseServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 在doGet()方法中调用doPost()方法,这样就可以在doPost()方法中集中处理所有请求
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 1.在所有request.getParameter()前面设置解析请求体的字符集
        request.setCharacterEncoding("UTF-8");

        // 2.从请求参数中获取method对应的数据
        String method = request.getParameter("method");

        // 3.通过反射调用method对应的方法
        // ①获取Class对象
        Class<? extends ModelBaseServlet> clazz = this.getClass();

        try {
            // ②获取method对应的Method对象
            Method methodObject = clazz.getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            // ③打开访问权限
            methodObject.setAccessible(true);

            // ④通过Method对象调用目标方法
            methodObject.invoke(this, request, response);
        } catch (Exception e) {
            e.printStackTrace();

            // 重要提醒:为了配合 TransactionFilter 实现事务控制,捕获的异常必须抛出。
            throw new RuntimeException(e);
        }
    }

}

5. 搭建环境:辅助功能

5.1 常量类

【后端】Maven 体系(五)_第14张图片

public class ImperialCourtConst {

    public static final String LOGIN_FAILED_MESSAGE = "账号、密码错误,不可进宫!";
    public static final String ACCESS_DENIED_MESSAGE = "宫闱禁地,不得擅入!";

}

5.2 MD5 加密工具方法

【后端】Maven 体系(五)_第15张图片

public class MD5Util {

    /**
     * 针对明文字符串执行MD5加密
     * @param source
     * @return
     */
    public static String encode(String source) {

        // 1.判断明文字符串是否有效
        if (source == null || "".equals(source)) {
            throw new RuntimeException("用于加密的明文不可为空");
        }

        // 2.声明算法名称
        String algorithm = "md5";

        // 3.获取MessageDigest对象
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 4.获取明文字符串对应的字节数组
        byte[] input = source.getBytes();

        // 5.执行加密
        byte[] output = messageDigest.digest(input);

        // 6.创建BigInteger对象
        int signum = 1;
        BigInteger bigInteger = new BigInteger(signum, output);

        // 7.按照16进制将bigInteger的值转换为字符串
        int radix = 16;
        String encoded = bigInteger.toString(radix).toUpperCase();

        return encoded;
    }

}

5.3 日志配置文件

【后端】Maven 体系(五)_第16张图片


<configuration debug="true">
    
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            
            
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%npattern>
            <charset>UTF-8charset>
        encoder>
    appender>

    
    
    <root level="INFO">
        
        <appender-ref ref="STDOUT" />
    root>

    
    <logger name="com.atguigu" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT" />
    logger>

configuration>

你可能感兴趣的:(后端,安全,java,开发语言)