尚硅谷JavaWeb笔记——书城项目(第三阶段:对第一阶段与第二阶段代码优化,第四阶段:使用EL表达式修改表单回显)

快来打我* 2022-11-01 10:52 466阅读 0赞

文章目录

  • 第三阶段(对第一第二阶段的代码进行优化)
    • 把HTML页面jsp动态化
    • 抽取页面中相同的内容
      • 动态显示登陆失败时的错误信息
        • 登陆失败页面设置
        • 注册失败页面设置
        • 登陆和注册的页面优化(合并)
    • 使用反射以及BaseServlet优化
    • 数据的封装和抽取BeanUtils的使用
      • WebUtils工具类
  • 第四阶段(使用EL修改修改表单回显)
    • 修改登陆页面
    • 修改注册页面

第三阶段(对第一第二阶段的代码进行优化)

把HTML页面jsp动态化

idea中的替换方法;按shift+command+R三个按钮调出替换页面并替换

在这里插入图片描述

抽取页面中相同的内容

需要替换的内容如下

  1. 页面中的base标签,css样式,jQuery文件一般都会放在common中作为其他页面的引用

    1. <%
    2. String scheme = request.getScheme(); // 获取协议
    3. String serverName = request.getServerName(); // 获取ip地址
    4. int serverPort = request.getServerPort(); // 获取端口号
    5. String contextPath = request.getContextPath(); // 获取工程名
    6. String basePath = scheme + "://" + serverName + ":" + serverPort + contextPath + "/"; //别忘了加 /
    7. pageContext.setAttribute("basePath", basePath);
    8. %>
    9. <base href="<%=basePath%>">
    10. <link type="text/css" rel="stylesheet" href="static/css/style.css" >
    11. <script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
    • 注意base标签应当动态获取,不能默认写死,不然一旦更换登录地址,可能出现页面无法访问
  2. 页面脚部的版权信息

    1. <div id="bottom">
    2. <span>
    3. 尚硅谷书城.Copyright ©2015
    4. </span>
    5. </div>

动态显示登陆失败时的错误信息

登陆错误回显示有如下两个需求以及对应的处理流程

在这里插入图片描述

登陆失败页面设置

如果无法顺利登陆,返回登陆失败的原因,同时保留登陆时的账号信息,因此在Servlet页面中应当有如下判断

因此,分析可知:当访问login.jsp页面时有两种情况,需要在jsp以及servlet中同时考虑如下两种情况

  • 情况一:第一次请求访问
  • 情况二:登陆失败请求重定向至login.jsp页面

    if (loginUser == null) {

    1. // 把错误信息,和回显的表单项信息,保存到Request域中
    2. req.setAttribute("msg","用户或密码错误!");
    3. req.setAttribute("username", username);
    4. // 跳回登录页面
    5. req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
    6. } else {
    7. // 登录 成功
    8. //跳到成功页面login_success.html
    9. req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
    10. }

在对应的jsp页面中也应当有如下内容

  1. <div class="tit">
  2. <h1>尚硅谷会员</h1>
  3. <a href="pages/user/regist.jsp">立即注册</a>
  4. </div>
  5. <div class="msg_cont">
  6. <b></b>
  7. <span class="errorMsg">
  8. ${ empty requestScope.msg ? "请输入用户名和密码":requestScope.msg }
  9. </span>
  10. </div>
  11. <div class="form">
  12. <form action="userServlet" method="post">
  13. <input type="hidden" name="action" value="login" />
  14. <label>用户名称:</label>
  15. <input class="itxt" type="text" placeholder="请输入用户名"
  16. autocomplete="off" tabindex="1" name="username"
  17. value="${requestScope.username}" />
  18. <br />
  19. <br />
  20. <label>用户密码:</label>
  21. <input class="itxt" type="password" placeholder="请输入密码"
  22. autocomplete="off" tabindex="1" name="password" />
  23. <br />
  24. <br />
  25. <input type="submit" value="登录" id="sub_btn" />
  26. </form>
  27. </div>

在这里插入图片描述

⭐️ 对应的页面信息与说明如上图所示,

⭐️ 很明显request域(该次请求有效)充当了信息传递的桥梁,重载了错误信息以及用户名称的回显。

注册失败页面设置

注册页面jsp代码与对应效果图如下

  1. <div class="login_form">
  2. <div class="login_box">
  3. <div class="tit">
  4. <h1>注册会员</h1>
  5. <span class="errorMsg"></span>
  6. </div>
  7. <div class="form">
  8. <form action="regietServlet" method="post">
  9. <label>用户名称:</label>
  10. <input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" id="username"/>
  11. <br/>
  12. <br/>
  13. <label>用户密码:</label>
  14. <input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password"/>
  15. <br/>
  16. <br/>
  17. <label>确认密码:</label>
  18. <input class="itxt" type="password" placeholder="确认密码" autocomplete="off" tabindex="1" name="repwd" id="repwd"/>
  19. <br/>
  20. <br/>
  21. <label>电子邮件:</label>
  22. <input class="itxt" type="text" placeholder="请输入邮箱地址" autocomplete="off" tabindex="1" name="email" id="email"/>
  23. <br/>
  24. <br/>
  25. <label>验证码:</label>
  26. <input class="itxt" type="text" name="code" style="width: 150px;" id="code"/>
  27. <img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px">
  28. <br/>
  29. <br/>
  30. <input type="submit" value="注册" id="sub_btn"/>
  31. </form>
  32. </div>
  33. </div>
  34. </div>

在这里插入图片描述

和登陆的设置一样,request与用于处理输出错误信息errorMsg,同时登陆失败时需要回显用户名称,电子邮件,验证码。两种注册失败的原因以及对应回显信息如下:

  • **注册失败原因一:**验证码错误,回显用户名、电子邮件、验证码(可选)
  • **注册失败原因二:**用户名已存在,回显用户名,电子邮件,验证码(可选)

对应的registServlet源码如下:

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. String username = request.getParameter("username");
  3. String password = request.getParameter("password");
  4. String email = request.getParameter("email");
  5. String code = request.getParameter("code");
  6. if ("abcd".equalsIgnoreCase(code)) { // 这里写死code用于测试
  7. if (userService.existUsername(username)) {
  8. // 将可以回显的数据写回request域中
  9. request.setAttribute("msg","该用户名已存在!");
  10. request.setAttribute("username",username);
  11. request.setAttribute("email",email);
  12. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
  13. }else {
  14. userService.login(new User(null, username, password, email));
  15. // System.out.println("好 注册OK! 正在跳转成功页面·····");
  16. request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request, response);
  17. }
  18. }else {
  19. request.setAttribute("msg","验证码错误!");
  20. request.setAttribute("username",username);
  21. request.setAttribute("email",email);
  22. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
  23. }
  24. }

对应的jsp页面源码如下

  1. <div class="login_form">
  2. <div class="login_box">
  3. <div class="tit">
  4. <h1>注册会员</h1>
  5. <span class="errorMsg">
  6. ${ requestScope.msg } <!-- 这里相对于前端页面做了修改。 -->
  7. </span>
  8. </div>
  9. <div class="form">
  10. <form action="registServlet" method="post">
  11. <label>用户名称:</label>
  12. <input class="itxt" type="text" placeholder="请输入用户名" value="${requestScope.username}" autocomplete="off" tabindex="1" name="username" id="username"/>
  13. <!-- 这里value值相对于前端页面做了修改。 -->
  14. <br/>
  15. <br/>
  16. <label>用户密码:</label>
  17. <input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password"/>
  18. <br/>
  19. <br/>
  20. <label>确认密码:</label>
  21. <input class="itxt" type="password" placeholder="确认密码" autocomplete="off" tabindex="1" name="repwd" id="repwd"/>
  22. <br/>
  23. <br/>
  24. <label>电子邮件:</label>
  25. <input class="itxt" type="text" placeholder="请输入邮箱地址" value="${requestScope.email}" autocomplete="off" tabindex="1" name="email" id="email"/>
  26. <!-- 这里email值相对于前端页面做了修改。 -->
  27. <br/>
  28. <br/>
  29. <label>验证码:</label>
  30. <input class="itxt" type="text" name="code" style="width: 150px;" id="code"/>
  31. <img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px">
  32. <br/>
  33. <br/>
  34. <input type="submit" value="注册" id="sub_btn"/>
  35. </form>
  36. </div>
  37. </div>
  38. </div>

登陆和注册的页面优化(合并)

我们希望将loginServlet和registServlet合并成为UserServlet,实现对页面的优化,可以通过如下过程实现

在这里插入图片描述

jsp页面的更改

需要在两个jsp页面中增加隐藏域

  • login.jsp:

    1. <input type="hidden" name="action" value="login" />
  • regist.jsp

    1. <input type="hidden" name="action" value="regist" />

在这里插入图片描述

UserServlet页面的更改

  1. public class UserServlet01 extends HttpServlet
  2. {
  3. private UserService userService = new UserServiceImpl();
  4. @Override
  5. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  6. String action = req.getParameter("action");
  7. if("login".equals(action)){
  8. login(req,resp);
  9. }else if("regist".equals(action)){
  10. regist(req,resp);
  11. }
  12. }
  13. /** * 处理登陆请求 * @param req * @param resp */
  14. protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15. // 1、获取请求的参数
  16. String username = req.getParameter("username");
  17. String password = req.getParameter("password");
  18. // 调用 userService.login()登录处理业务
  19. User loginUser = userService.login(new User(null, username, password, null));
  20. // 如果等于null,说明登录 失败!
  21. if (loginUser == null) {
  22. // 把错误信息,和回显的表单项信息,保存到Request域中
  23. req.setAttribute("msg","用户或密码错误!");
  24. req.setAttribute("username", username);
  25. // 跳回登录页面
  26. req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
  27. } else {
  28. // 登录 成功
  29. //跳到成功页面login_success.html
  30. req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
  31. }
  32. }
  33. /** * 处理注册请求 * @param req * @param resp */
  34. protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
  35. String username = request.getParameter("username");
  36. String password = request.getParameter("password");
  37. String email = request.getParameter("email");
  38. String code = request.getParameter("code");
  39. System.out.println(code);
  40. if ("abcd".equalsIgnoreCase(code)) {
  41. if (userService.existUsername(username)) {
  42. // System.out.println("存在了!不能注册 正在跳转注册页面·····");
  43. request.setAttribute("msg","该用户名已存在!");
  44. request.setAttribute("username",username);
  45. request.setAttribute("email",email);
  46. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
  47. }else {
  48. userService.login(new User(null, username, password, email));
  49. // System.out.println("好 注册OK! 正在跳转成功页面·····");
  50. request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request, response);
  51. }
  52. }else {
  53. // System.out.println("不争气,,验证码不对!");
  54. request.setAttribute("msg","验证码错误!");
  55. request.setAttribute("username",username);
  56. request.setAttribute("email",email);
  57. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
  58. }
  59. }
  60. }

使用反射以及BaseServlet优化

注意到如下代码段中从request域中得到的内容其实和方法名相同,因此考虑使用反射机制,写一段通用代码,直接获取对应的方法

  1. String action = req.getParameter("action");
  2. if("login".equals(action)){
  3. login(req,resp);
  4. }else if("regist".equals(action)){
  5. regist(req,resp);
  6. }

具体过程见如下代码

  1. String action = request.getParameter("action");
  2. // 获取action业务鉴别字符串,获取相应的业务 方法反射对象
  3. Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); // 使用反射获取目标业务名
  4. // 调用目标业务 方法
  5. method.invoke(this, request, response);

进一步,由于该过程是每一个模块都可能会用到的过程,因此考虑将其按照如下的方式抽取出来

在这里插入图片描述

构建一个BaseServlet程序,让各个模块继承该程序,对应代码如下:

  1. public abstract class BaseServlet extends HttpServlet {
  2. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  3. doPost(request, response);
  4. }
  5. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  6. // 解决post请求中文乱码问题
  7. // 一定要在获取请求参数之前调用才有效
  8. request.setCharacterEncoding("UTF-8");
  9. // 解决响应中文乱码
  10. response.setContentType("text/html; charset=UTF-8");
  11. String action = request.getParameter("action");
  12. try {
  13. // 获取action业务鉴别字符串,获取相应的业务 方法反射对象
  14. Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
  15. // 调用目标业务 方法
  16. method.invoke(this, request, response);
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. throw new RuntimeException(e);//抛给Filter过滤器
  20. }
  21. }
  22. }

然后在对应的其他模块servlet中写业务逻辑方法

bookservlet模块

在这里插入图片描述

UserServlet模块

在这里插入图片描述

数据的封装和抽取BeanUtils的使用

BeanUtils工具类可以一次性地把所有请求的参数都注入到JavaBean中。出现这种需求的原因是:

  • 某个业务框中存在很多用户输入的数据内容,此时我们就一条一条的获取并注入JavaBean对象中,这太过于麻烦,于是BeanUtils诞生了。

BeanUtils不是jdk的类,是第三方的工具类,所以需要导包,导包内容如下

在这里插入图片描述

可以使用BeanUtils包将用户的输入数据注册至JavaBean对象中,因此可以写一个WebUtils类来完成该操作:

WebUtils工具类

  1. public class WebUtils {
  2. /** * 把Map中的值注入到对应的JavaBean属性中。 * @param value * @param bean */
  3. public static<T> T copyParamToBean(Map value, T bean){
  4. try {
  5. System.out.println("BeanUtils.populate()上一句······");
  6. /** * 把所有请求的参数都注入到user对象中 */
  7. BeanUtils.populate(bean, value); // 核心语句
  8. System.out.println("BeanUtils.populate()下一句······");
  9. } catch (IllegalAccessException e) {
  10. e.printStackTrace();
  11. } catch (InvocationTargetException e) {
  12. e.printStackTrace();
  13. }
  14. return bean;
  15. }
  16. }

关于populate方法的说明:

  • 源码中对给方法有如下注释

在这里插入图片描述

  • 其需要给定待注入的JavaBean对象,以及对应的properties(键值对参数)。该方法利用反射调用了对应javaBean中的setxxx()方法,因此一定要保证传递进入的paraName和javaBean中的属性值相同,这样才能成功调用setxxx()方法。

因此,在同时考虑泛型的情况下在该自定义的工具类中要从UserServlet中传递的参数应当为(Map value, T bean),而不是(HttpServletRequest req, Object bean)

这么做的原因:将Map的值注入JavaBean的需求很常见,不只有Web层有这种需求,DAO层,Service层,Web层都可能会有这种需求,如果这里写成了(HttpServletRequest req, Object bean),DAO层和Service层就无法使用该方法,如果写成前者的话,三层都可以使用。使用后者就会使得代码的耦合度过高——优雅

对应的UserServlet类中也需要做如下修改

  1. // 1、获取请求的参数
  2. String username = request.getParameter("username");
  3. String password = request.getParameter("password");
  4. String email = request.getParameter("email");
  5. String code = request.getParameter("code");
  6. // 上述四行代码可以用如下一行代码完成替换
  7. User user = WebUtils.copyParamToBean(request.getParameterMap(), new User());
  8. // 这里传递的参数为参数的键值对,原因如上
  • 在上述代码中,即可获得成功注入请求数据的user对象

第四阶段(使用EL修改修改表单回显)

修改登陆页面

  1. <!-- 不使用EL表达式 -->
  2. <% request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg")%>
  3. <!-- 使用EL表达式输入错误信息 -->
  4. ${ empty requestScope.msg ? "请输入用户名和密码":requestScope.msg }
  5. <!-- 使用EL表达式回显用户名 -->
  6. <input class="itxt" type="text" placeholder="请输入用户名"
  7. autocomplete="off" tabindex="1" name="username"
  8. value="${requestScope.username}" />

修改注册页面

  1. <!-- 使用EL表达式输入错误信息 -->
  2. ${ requestScope.msg }
  3. <!-- 使用EL表达式回显用户名 -->
  4. <label>用户名称:</label>
  5. <input class="itxt" type="text" placeholder="请输入用户名"
  6. value="${requestScope.username}"
  7. autocomplete="off" tabindex="1" name="username" id="username"/>
  8. <!-- 使用EL表达式回显电子邮件 -->
  9. <label>电子邮件:</label>
  10. <input class="itxt" type="text" placeholder="请输入邮箱地址"
  11. value="${requestScope.email}"
  12. autocomplete="off" tabindex="1" name="email" id="email"/>

发表评论

表情:
评论列表 (有 0 条评论,466人围观)

还没有评论,来说两句吧...

相关阅读