> 文档中心 > Servlet | Servlet基于注解式开发、使用模板方法设计模式解决类爆炸

Servlet | Servlet基于注解式开发、使用模板方法设计模式解决类爆炸

目录

一:Servlet基于注解式开发

二:使用模板方法设计模式解决类爆炸


一:Servlet基于注解式开发

使用注解解决web.xml配置文件问题!

1、分析前面写的oa项目中的web.xml文件

 (1)目前只是一个单表的CRUD,没有复杂的业务逻辑,很简单的功能。web.xml文件中就有如此多的配置信息。如果采用这种方式,对于一个大的项目来说,这样的话web.xml文件会非常庞大,有可能最终会达到几十兆。

(2)在web.xml文件中进行servlet信息的配置,显然开发效率比较低,每一个类都需要配置一下。

(3)并且在web.xml文件中的配置是很少被修改的,所以这种配置信息能不能直接写到java类当中呢?当然是可以的!

2、注解式开发

(1)Servlet3.0版本之后,推出了各种Servlet基于注解式开发。

(2)优点是开发效率高,不需要编写大量的配置信息。直接在java类上使用注解进行标注,

 web.xml文件体积变小!

(3)并不是说注解有了之后,web.xml文件就不需要了;有一些需要变化的信息,还是要配置到web.xml文件中;一般都是 注解+配置文件 的开发模式。

3、第一个注解式开发

javax.servlet.annotation.WebServlet // 在这个包下

(1)在Servlet类上使用:@WebServlet,WebServlet注解中常用的属性

①name属性:用来指定Servlet的名字。等同于:

String name() default "";

②urlPatterns属性:用来指定Servlet的映射路径,可以指定多个字符串。等同于:

String[] urlPatterns() default {};

③loadOnStartUp属性:用来指定在服务器启动阶段是否加载该Servlet。等同于:

int loadOnStartup() default -1;

④initParams属性:用来初始化参数的标签。等同于:

WebInitParam[] initParams() default {};// WebInitParam也是一个注解,注解里面套注解
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WebInitParam {    String name();    String value();    String description() default "";}

(2)value属性:value属性和urlPatterns属性一致,都是可以用来指定Servlet的映射路径的。只不过当注解的属性名是value的时候,使用注解的时候,value属性名是可以省略

(3)注意:属性是一个数组,如果数组中只有一个元素,使用该注解的时候,属性值的大括号可以省略。

(4)注解对象的使用格式: @注解名称(属性名=属性值, 属性名=属性值, 属性名=属性值....)

(5)例:不使用web.xml配置的方式,使用注解的方式进行开发

package com.bjpowernode.javaweb.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.Enumeration;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.javaweb.servlet * @Project:JavaWeb * @name:HelloServlet * @Date:2022/11/15 14:17 */@WebServlet(name="hello", urlPatterns = {"/hello1","/hello2"}, loadOnStartup = 1, initParams = {@WebInitParam(name="username",value="root"),@WebInitParam(name="password",value="123")})public class HelloServlet extends HttpServlet {    // 无参构造方法    // 前面在注解中配置了loadOnStartup = 1,表示在服务器启动时就加载Servlet    public HelloServlet() { System.out.println("无参构造方法HelloServlet方法执行完了");    }    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { response.setContentType("text/html;chasrset=UTF-8"); PrintWriter out = response.getWriter(); // 获取Servlet name String servletName = this.getServletName(); out.print("servlet name = " + servletName + "
"); // servlet name = hello // 获取Servlet path String servletPath = request.getServletPath(); out.print("servlet path = " + servletPath + "
"); // servlet path = /hello1 // 获取初始化参数 Enumeration initParameterNames = this.getInitParameterNames(); while(initParameterNames.hasMoreElements()){ String name = initParameterNames.nextElement(); // 通过key获取value String value = getInitParameter(name); out.print(name + "=" + value + "
"); // username=root password=123 } }}

(6)通过反射机制拿到注解的信息

package com.bjpowernode.javaweb.servlet;import javax.servlet.annotation.WebServlet;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.javaweb.servlet * @Project:JavaWeb * @name:ReflectAnnotation * @Date:2022/11/15 16:23 */public class ReflectAnnotation {    public static void main(String[] args) throws Exception { // 使用反射机制将类上面的注解进行解析 // 获取类Class对象 Class helloClass = Class.forName("com.bjpowernode.javaweb.servlet.HelloServlet"); // 获取这个类上面的注解对象 // 先判断这个类上面有没有这个注解对象,如果有这个注解对象,就获取该注解对象。 boolean annotationPresent = helloClass.isAnnotationPresent(WebServlet.class); if (annotationPresent){     // 获取这个类上面的注解对象     WebServlet annotation = helloClass.getAnnotation(WebServlet.class);     // 获取注解的urlPatterns属性值     String[] values = annotation.urlPatterns();     for (int i = 0; i < values.length; i++) {  System.out.println(values[i]);// /hello1 /hello2     } }    }}

二:使用模板方法设计模式解决类爆炸

使用模板方法设计模式解决类爆炸问题!

(1)上面的注解解决了配置文件的问题;但是现在的oa项目仍然存在一个代码比较臃肿的问题。

①一个单标的CRUD,就写了6个Servlet。如果一个复杂的业务系统,这种开发方式,显然会导致类爆炸。(类的数量太大)

②怎么解决这个类爆炸问题?可以使用模板方法设计模式。

(2)怎么解决类爆炸问题?

①以前的设计方式是一个请求一个Servlet类,导致类爆炸。

②优化:让一个请求对应一个方法,一个业务才对应一个Servlet类。

(3)通过使用注解的方式和模板设计方法的模式,对oa项目:单表的CRUD操作进行优化

①重写service方法(并没有重写doGet或者doPost)
②并不知道发送的是doGet或者doPost请求,所以重写它们的上一层方法
③也可以doGet或者doPost请求都重写,但是要在doGet调doPost,或者doPost调doGet

package com.bjpowernode.oa.web.action;import com.bjpowernode.oa.utils.DBUtil;import jakarta.servlet.ServletException;import jakarta.servlet.annotation.WebServlet;import jakarta.servlet.http.HttpServlet;import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;// 模板类,省略了value@WebServlet({"/dept/list", "/dept/save", "/dept/edit", "/dept/detail", "/dept/delete", "/dept/modify"})// 模糊匹配// 只要请求路径是以"/dept"开始的,都走这个Servlet。//@WebServlet("/dept/*")public class DeptServlet extends HttpServlet {    // 模板方法      @Override    protected void service(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { // 获取servlet path String servletPath = request.getServletPath(); if("/dept/list".equals(servletPath)){     doList(request, response); } else if("/dept/save".equals(servletPath)){     doSave(request, response); } else if("/dept/edit".equals(servletPath)){     doEdit(request, response); } else if("/dept/detail".equals(servletPath)){     doDetail(request, response); } else if("/dept/delete".equals(servletPath)){     doDel(request, response); } else if("/dept/modify".equals(servletPath)){     doModify(request, response); }    }    private void doList(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { // 获取应用的根路径 String contextPath = request.getContextPath(); // 设置响应的内容类型以及字符集。防止中文乱码问题。 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(""); out.print(""); out.print(""); out.print(""); out.print("<a href="https://www.csdndoc.com/tag/%e9%83%a8%e9%97%a8" title="View all posts in 部门" target="_blank" style="color:#0ec3f3;font-size: 18px;font-weight: 600;">部门</a>列表页面"); out.print(""); out.print("    function del(dno){"); out.print(" if(window.confirm('亲,删了不可恢复哦!')){"); out.print("     document.location.href = '"+contextPath+"/dept/delete?deptno=' + dno"); out.print(" }"); out.print("    }"); out.print(""); out.print(""); out.print(""); out.print("

部门列表

"); out.print("
"); out.print(""); out.print(""); out.print(""); out.print(""); out.print(""); out.print(""); out.print(""); /*上面一部分是死的*/ // 连接数据库,查询所有的部门 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 获取连接 conn = DBUtil.getConnection(); // 获取预编译的数据库操作对象 String sql = "select deptno as a,dname,loc from dept"; ps = conn.prepareStatement(sql); // 执行SQL语句 rs = ps.executeQuery(); // 处理结果集 int i = 0; while(rs.next()){ String deptno = rs.getString("a"); String dname = rs.getString("dname"); String loc = rs.getString("loc"); out.print(""); out.print(""); out.print(""); out.print(""); out.print(""); out.print(""); } } catch (SQLException e) { e.printStackTrace(); } finally { // 释放资源 DBUtil.close(conn, ps, rs); } /*下面一部分是死的*/ out.print("
序号部门编号部门名称操作
"+(++i)+""+deptno+""+dname+""); out.print("删除"); out.print("修改"); out.print("详情"); out.print("
"); out.print("
"); out.print("新增部门"); out.print(""); out.print(""); } private void doSave(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取部门的信息 // 注意乱码问题(Tomcat10不会出现这个问题) request.setCharacterEncoding("UTF-8"); String deptno = request.getParameter("deptno"); String dname = request.getParameter("dname"); String loc = request.getParameter("loc"); // 连接数据库执行insert语句 Connection conn = null; PreparedStatement ps = null; int count = 0; try { conn = DBUtil.getConnection(); String sql = "insert into dept(deptno, dname, loc) values(?,?,?)"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); ps.setString(2, dname); ps.setString(3, loc); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, ps, null); } if (count == 1) { // 保存成功跳转到列表页面 // 转发是一次请求。 //request.getRequestDispatcher("/dept/list").forward(request, response); // 这里最好使用重定向(浏览器会发一次全新的请求。) // 浏览器在地址栏上发送请求,这个请求是get请求。 response.sendRedirect(request.getContextPath() + "/dept/list"); }else{ // 保存失败跳转到错误页面 //request.getRequestDispatcher("/error.html").forward(request, response); // 这里也建议使用重定向。 response.sendRedirect(request.getContextPath() + "/error.html"); } } private void doEdit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取应用的根路径。 String contextPath = request.getContextPath(); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(""); out.print(""); out.print(""); out.print(""); out.print("修改部门"); out.print(""); out.print(""); out.print("

修改部门

"); out.print("
"); out.print(""); // 获取部门编号 String deptno = request.getParameter("deptno"); // 连接数据库,根据部门编号查询部门的信息。 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); String sql = "select dname, loc as location from dept where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); rs = ps.executeQuery(); // 这个结果集中只有一条记录。 if(rs.next()){ String dname = rs.getString("dname"); String location = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。 // 输出动态网页。 out.print(" 部门编号
"); out.print(" 部门名称
"); out.print(" 部门位置
"); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, ps, rs); } out.print("
"); out.print(""); out.print(""); out.print(""); } private void doDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(""); out.print(""); out.print(""); out.print(""); out.print("部门详情"); out.print(""); out.print(""); out.print("

部门详情

"); out.print("
"); // 获取部门编号 // /oa/dept/detail?fdsafdsas=30 // 虽然是提交的30,但是服务器获取的是"30"这个字符串。 String deptno = request.getParameter("fdsafdsas"); // 连接数据库,根据部门编号查询部门信息。 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); String sql = "select dname,loc from dept where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); rs = ps.executeQuery(); // 这个结果集一定只有一条记录。 if(rs.next()){ String dname = rs.getString("dname"); String loc = rs.getString("loc"); out.print("部门编号:"+deptno+"
"); out.print("部门名称:"+dname+"
"); out.print("部门位置:"+loc+"
"); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, ps, rs); } out.print(""); out.print(""); out.print(""); } private void doDel(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 根据部门编号,删除部门。 // 获取部门编号 String deptno = request.getParameter("deptno"); // 连接数据库删除数据 Connection conn = null; PreparedStatement ps = null; int count = 0; try { conn = DBUtil.getConnection(); // 开启事务(自动提交机制关闭) conn.setAutoCommit(false); String sql = "delete from dept where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); // 返回值是:影响了数据库表当中多少条记录。 count = ps.executeUpdate(); // 事务提交 conn.commit(); } catch (SQLException e) { // 遇到异常要回滚 if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); } finally { DBUtil.close(conn, ps, null); } // 判断删除成功了还是失败了。 if (count == 1) { //删除成功 //仍然跳转到部门列表页面 //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。 //request.getRequestDispatcher("/dept/list").forward(request, response); response.sendRedirect(request.getContextPath() + "/dept/list"); }else{ // 删除失败 //request.getRequestDispatcher("/error.html").forward(request, response); response.sendRedirect(request.getContextPath() + "/error.html"); } } private void doModify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 解决请求体的中文乱码问题。 request.setCharacterEncoding("UTF-8"); // 获取表单中的数据 String deptno = request.getParameter("deptno"); String dname = request.getParameter("dname"); String loc = request.getParameter("loc"); // 连接数据库执行更新语句 Connection conn = null; PreparedStatement ps = null; int count = 0; try { conn = DBUtil.getConnection(); String sql = "update dept set dname = ?, loc = ? where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1, dname); ps.setString(2, loc); ps.setString(3, deptno); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, ps, null); } if (count == 1) { // 更新成功 // 跳转到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet) //request.getRequestDispatcher("/dept/list").forward(request, response); response.sendRedirect(request.getContextPath() + "/dept/list"); }else{ // 更新失败 //request.getRequestDispatcher("/error.html").forward(request, response); response.sendRedirect(request.getContextPath() + "/error.html"); } }}

总结:使用了注解式开发优化了web.xml撑爆问题;使用模板方法设计模式解决了类爆炸问题;很大程度的优化了oa项目!

读书笔记网