• 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属性:用来初始化参数的标签。等同于:

    1. WebInitParam[] initParams() default {};
    2. // WebInitParam也是一个注解,注解里面套注解
    1. @Target({ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. public @interface WebInitParam {
    5. String name();
    6. String value();
    7. String description() default "";
    8. }

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

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

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

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

    1. package com.bjpowernode.javaweb.servlet;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebInitParam;
    4. import javax.servlet.annotation.WebServlet;
    5. import javax.servlet.http.HttpServlet;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. import java.io.IOException;
    9. import java.io.PrintWriter;
    10. import java.util.Enumeration;
    11. /**
    12. * @Author:朗朗乾坤
    13. * @Package:com.bjpowernode.javaweb.servlet
    14. * @Project:JavaWeb
    15. * @name:HelloServlet
    16. * @Date:2022/11/15 14:17
    17. */
    18. @WebServlet(name="hello",
    19. urlPatterns = {"/hello1","/hello2"},
    20. loadOnStartup = 1,
    21. initParams = {@WebInitParam(name="username",value="root"),@WebInitParam(name="password",value="123")})
    22. public class HelloServlet extends HttpServlet {
    23. // 无参构造方法
    24. // 前面在注解中配置了loadOnStartup = 1,表示在服务器启动时就加载Servlet
    25. public HelloServlet() {
    26. System.out.println("无参构造方法HelloServlet方法执行完了");
    27. }
    28. @Override
    29. protected void doGet(HttpServletRequest request, HttpServletResponse response)
    30. throws ServletException, IOException {
    31. response.setContentType("text/html;chasrset=UTF-8");
    32. PrintWriter out = response.getWriter();
    33. // 获取Servlet name
    34. String servletName = this.getServletName();
    35. out.print("servlet name = " + servletName + "
      "
      ); // servlet name = hello
    36. // 获取Servlet path
    37. String servletPath = request.getServletPath();
    38. out.print("servlet path = " + servletPath + "
      "
      ); // servlet path = /hello1
    39. // 获取初始化参数
    40. Enumeration initParameterNames = this.getInitParameterNames();
    41. while(initParameterNames.hasMoreElements()){
    42. String name = initParameterNames.nextElement();
    43. // 通过key获取value
    44. String value = getInitParameter(name);
    45. out.print(name + "=" + value + "
      "
      ); // username=root password=123
    46. }
    47. }
    48. }

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

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

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

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

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

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

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

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

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

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

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

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

    1. package com.bjpowernode.oa.web.action;
    2. import com.bjpowernode.oa.utils.DBUtil;
    3. import jakarta.servlet.ServletException;
    4. import jakarta.servlet.annotation.WebServlet;
    5. import jakarta.servlet.http.HttpServlet;
    6. import jakarta.servlet.http.HttpServletRequest;
    7. import jakarta.servlet.http.HttpServletResponse;
    8. import java.io.IOException;
    9. import java.io.PrintWriter;
    10. import java.sql.Connection;
    11. import java.sql.PreparedStatement;
    12. import java.sql.ResultSet;
    13. import java.sql.SQLException;
    14. // 模板类,省略了value
    15. @WebServlet({"/dept/list", "/dept/save", "/dept/edit", "/dept/detail", "/dept/delete", "/dept/modify"})
    16. // 模糊匹配
    17. // 只要请求路径是以"/dept"开始的,都走这个Servlet。
    18. //@WebServlet("/dept/*")
    19. public class DeptServlet extends HttpServlet {
    20. // 模板方法
    21. @Override
    22. protected void service(HttpServletRequest request, HttpServletResponse response)
    23. throws ServletException, IOException {
    24. // 获取servlet path
    25. String servletPath = request.getServletPath();
    26. if("/dept/list".equals(servletPath)){
    27. doList(request, response);
    28. } else if("/dept/save".equals(servletPath)){
    29. doSave(request, response);
    30. } else if("/dept/edit".equals(servletPath)){
    31. doEdit(request, response);
    32. } else if("/dept/detail".equals(servletPath)){
    33. doDetail(request, response);
    34. } else if("/dept/delete".equals(servletPath)){
    35. doDel(request, response);
    36. } else if("/dept/modify".equals(servletPath)){
    37. doModify(request, response);
    38. }
    39. }
    40. private void doList(HttpServletRequest request, HttpServletResponse response)
    41. throws ServletException, IOException {
    42. // 获取应用的根路径
    43. String contextPath = request.getContextPath();
    44. // 设置响应的内容类型以及字符集。防止中文乱码问题。
    45. response.setContentType("text/html;charset=UTF-8");
    46. PrintWriter out = response.getWriter();
    47. out.print("");
    48. out.print("");
    49. out.print(" ");
    50. out.print(" ");
    51. out.print(" 部门列表页面");
    52. out.print("");
    53. out.print(" ");
    54. out.print(" ");
    55. out.print("

      部门列表

      "
      );
    56. out.print("
      "
      );
    57. out.print(" ");
    58. out.print("
    59. ");
    60. out.print("
    61. ");
    62. out.print("
    63. ");
    64. out.print("
    65. ");
    66. out.print("
    67. ");
    68. out.print("
    69. ");
    70. /*上面一部分是死的*/
    71. // 连接数据库,查询所有的部门
    72. Connection conn = null;
    73. PreparedStatement ps = null;
    74. ResultSet rs = null;
    75. try {
    76. // 获取连接
    77. conn = DBUtil.getConnection();
    78. // 获取预编译的数据库操作对象
    79. String sql = "select deptno as a,dname,loc from dept";
    80. ps = conn.prepareStatement(sql);
    81. // 执行SQL语句
    82. rs = ps.executeQuery();
    83. // 处理结果集
    84. int i = 0;
    85. while(rs.next()){
    86. String deptno = rs.getString("a");
    87. String dname = rs.getString("dname");
    88. String loc = rs.getString("loc");
    89. out.print("
    90. ");
    91. out.print("
    92. ");
    93. out.print("
    94. ");
    95. out.print("
    96. ");
    97. out.print("
    98. ");
    99. out.print("
    100. ");
    101. }
    102. } catch (SQLException e) {
    103. e.printStackTrace();
    104. } finally {
    105. // 释放资源
    106. DBUtil.close(conn, ps, rs);
    107. }
    108. /*下面一部分是死的*/
    109. out.print("
    110. 序号部门编号部门名称操作
      "+(++i)+""+deptno+""+dname+"");
    111. out.print(" 删除");
    112. out.print(" 修改");
    113. out.print(" 详情");
    114. out.print("
    115. "
      );
    116. out.print("
      "
      );
    117. out.print(" 新增部门");
    118. out.print(" ");
    119. out.print("");
    120. }
    121. private void doSave(HttpServletRequest request, HttpServletResponse response)
    122. throws ServletException, IOException {
    123. // 获取部门的信息
    124. // 注意乱码问题(Tomcat10不会出现这个问题)
    125. request.setCharacterEncoding("UTF-8");
    126. String deptno = request.getParameter("deptno");
    127. String dname = request.getParameter("dname");
    128. String loc = request.getParameter("loc");
    129. // 连接数据库执行insert语句
    130. Connection conn = null;
    131. PreparedStatement ps = null;
    132. int count = 0;
    133. try {
    134. conn = DBUtil.getConnection();
    135. String sql = "insert into dept(deptno, dname, loc) values(?,?,?)";
    136. ps = conn.prepareStatement(sql);
    137. ps.setString(1, deptno);
    138. ps.setString(2, dname);
    139. ps.setString(3, loc);
    140. count = ps.executeUpdate();
    141. } catch (SQLException e) {
    142. e.printStackTrace();
    143. } finally {
    144. DBUtil.close(conn, ps, null);
    145. }
    146. if (count == 1) {
    147. // 保存成功跳转到列表页面
    148. // 转发是一次请求。
    149. //request.getRequestDispatcher("/dept/list").forward(request, response);
    150. // 这里最好使用重定向(浏览器会发一次全新的请求。)
    151. // 浏览器在地址栏上发送请求,这个请求是get请求。
    152. response.sendRedirect(request.getContextPath() + "/dept/list");
    153. }else{
    154. // 保存失败跳转到错误页面
    155. //request.getRequestDispatcher("/error.html").forward(request, response);
    156. // 这里也建议使用重定向。
    157. response.sendRedirect(request.getContextPath() + "/error.html");
    158. }
    159. }
    160. private void doEdit(HttpServletRequest request, HttpServletResponse response)
    161. throws ServletException, IOException {
    162. // 获取应用的根路径。
    163. String contextPath = request.getContextPath();
    164. response.setContentType("text/html;charset=UTF-8");
    165. PrintWriter out = response.getWriter();
    166. out.print("");
    167. out.print("");
    168. out.print(" ");
    169. out.print(" ");
    170. out.print(" 修改部门");
    171. out.print(" ");
    172. out.print(" ");
    173. out.print("

      修改部门

      "
      );
    174. out.print("
      "
      );
    175. out.print("
      ");
    176. // 获取部门编号
    177. String deptno = request.getParameter("deptno");
    178. // 连接数据库,根据部门编号查询部门的信息。
    179. Connection conn = null;
    180. PreparedStatement ps = null;
    181. ResultSet rs = null;
    182. try {
    183. conn = DBUtil.getConnection();
    184. String sql = "select dname, loc as location from dept where deptno = ?";
    185. ps = conn.prepareStatement(sql);
    186. ps.setString(1, deptno);
    187. rs = ps.executeQuery();
    188. // 这个结果集中只有一条记录。
    189. if(rs.next()){
    190. String dname = rs.getString("dname");
    191. String location = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。
    192. // 输出动态网页。
    193. out.print(" 部门编号
      "
      );
    194. out.print(" 部门名称
      "
      );
    195. out.print(" 部门位置
      "
      );
    196. }
    197. } catch (SQLException e) {
    198. e.printStackTrace();
    199. } finally {
    200. DBUtil.close(conn, ps, rs);
    201. }
    202. out.print("
      "
      );
    203. out.print(" ");
    204. out.print(" ");
    205. out.print("");
    206. }
    207. private void doDetail(HttpServletRequest request, HttpServletResponse response)
    208. throws ServletException, IOException {
    209. response.setContentType("text/html;charset=UTF-8");
    210. PrintWriter out = response.getWriter();
    211. out.print("");
    212. out.print("");
    213. out.print(" ");
    214. out.print(" ");
    215. out.print(" 部门详情");
    216. out.print(" ");
    217. out.print(" ");
    218. out.print("

      部门详情

      "
      );
    219. out.print("
      "
      );
    220. // 获取部门编号
    221. // /oa/dept/detail?fdsafdsas=30
    222. // 虽然是提交的30,但是服务器获取的是"30"这个字符串。
    223. String deptno = request.getParameter("fdsafdsas");
    224. // 连接数据库,根据部门编号查询部门信息。
    225. Connection conn = null;
    226. PreparedStatement ps = null;
    227. ResultSet rs = null;
    228. try {
    229. conn = DBUtil.getConnection();
    230. String sql = "select dname,loc from dept where deptno = ?";
    231. ps = conn.prepareStatement(sql);
    232. ps.setString(1, deptno);
    233. rs = ps.executeQuery();
    234. // 这个结果集一定只有一条记录。
    235. if(rs.next()){
    236. String dname = rs.getString("dname");
    237. String loc = rs.getString("loc");
    238. out.print("部门编号:"+deptno+"
      "
      );
    239. out.print("部门名称:"+dname+"
      "
      );
    240. out.print("部门位置:"+loc+"
      "
      );
    241. }
    242. } catch (SQLException e) {
    243. e.printStackTrace();
    244. } finally {
    245. DBUtil.close(conn, ps, rs);
    246. }
    247. out.print(" ");
    248. out.print(" ");
    249. out.print("");
    250. }
    251. private void doDel(HttpServletRequest request, HttpServletResponse response)
    252. throws ServletException, IOException {
    253. // 根据部门编号,删除部门。
    254. // 获取部门编号
    255. String deptno = request.getParameter("deptno");
    256. // 连接数据库删除数据
    257. Connection conn = null;
    258. PreparedStatement ps = null;
    259. int count = 0;
    260. try {
    261. conn = DBUtil.getConnection();
    262. // 开启事务(自动提交机制关闭)
    263. conn.setAutoCommit(false);
    264. String sql = "delete from dept where deptno = ?";
    265. ps = conn.prepareStatement(sql);
    266. ps.setString(1, deptno);
    267. // 返回值是:影响了数据库表当中多少条记录。
    268. count = ps.executeUpdate();
    269. // 事务提交
    270. conn.commit();
    271. } catch (SQLException e) {
    272. // 遇到异常要回滚
    273. if (conn != null) {
    274. try {
    275. conn.rollback();
    276. } catch (SQLException ex) {
    277. ex.printStackTrace();
    278. }
    279. }
    280. e.printStackTrace();
    281. } finally {
    282. DBUtil.close(conn, ps, null);
    283. }
    284. // 判断删除成功了还是失败了。
    285. if (count == 1) {
    286. //删除成功
    287. //仍然跳转到部门列表页面
    288. //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
    289. //request.getRequestDispatcher("/dept/list").forward(request, response);
    290. response.sendRedirect(request.getContextPath() + "/dept/list");
    291. }else{
    292. // 删除失败
    293. //request.getRequestDispatcher("/error.html").forward(request, response);
    294. response.sendRedirect(request.getContextPath() + "/error.html");
    295. }
    296. }
    297. private void doModify(HttpServletRequest request, HttpServletResponse response)
    298. throws ServletException, IOException {
    299. // 解决请求体的中文乱码问题。
    300. request.setCharacterEncoding("UTF-8");
    301. // 获取表单中的数据
    302. String deptno = request.getParameter("deptno");
    303. String dname = request.getParameter("dname");
    304. String loc = request.getParameter("loc");
    305. // 连接数据库执行更新语句
    306. Connection conn = null;
    307. PreparedStatement ps = null;
    308. int count = 0;
    309. try {
    310. conn = DBUtil.getConnection();
    311. String sql = "update dept set dname = ?, loc = ? where deptno = ?";
    312. ps = conn.prepareStatement(sql);
    313. ps.setString(1, dname);
    314. ps.setString(2, loc);
    315. ps.setString(3, deptno);
    316. count = ps.executeUpdate();
    317. } catch (SQLException e) {
    318. e.printStackTrace();
    319. } finally {
    320. DBUtil.close(conn, ps, null);
    321. }
    322. if (count == 1) {
    323. // 更新成功
    324. // 跳转到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet)
    325. //request.getRequestDispatcher("/dept/list").forward(request, response);
    326. response.sendRedirect(request.getContextPath() + "/dept/list");
    327. }else{
    328. // 更新失败
    329. //request.getRequestDispatcher("/error.html").forward(request, response);
    330. response.sendRedirect(request.getContextPath() + "/error.html");
    331. }
    332. }
    333. }

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

  • 相关阅读:
    ollama 模型国内加速下载,制作自定义Modelfile模型文件
    【NOI模拟赛】思门弄数(数论,链表)
    Docker实战:docker compose 搭建Sonar
    10M25DCF484C8G(FPGA) AMY-6M-0002 BGA GPS模块
    数字藏品值得探究,依然是广阔的大海播
    java计算机毕业设计springboot+vue南天在线求助系统
    c# 项目重构,创建新的解决方案
    ENVI:如何进行遥感图像的分类?(决策树模型)
    linux 中jenkins启动重启停止命令 改端口
    three.js 字体精简处理
  • 原文地址:https://blog.csdn.net/m0_61933976/article/details/127865887