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

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

把HTML页面jsp动态化

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

在这里插入图片描述

抽取页面中相同的内容

需要替换的内容如下

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

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

    <div id="bottom">
    		<span>
    			尚硅谷书城.Copyright &copy;2015
    		</span>
    </div>
    

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

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

在这里插入图片描述

登陆失败页面设置

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

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

  • 情况一:第一次请求访问
  • 情况二:登陆失败请求重定向至login.jsp页面
if (loginUser == null) {
            // 把错误信息,和回显的表单项信息,保存到Request域中
            req.setAttribute("msg","用户或密码错误!");
            req.setAttribute("username", username);
            //   跳回登录页面
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
        } else {
            // 登录 成功
            //跳到成功页面login_success.html
            req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
        }

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

<div class="tit">
  <h1>尚硅谷会员</h1>
  <a href="pages/user/regist.jsp">立即注册</a>
</div>
<div class="msg_cont">
  <b></b>
  <span class="errorMsg">
    ${ empty requestScope.msg ? "请输入用户名和密码":requestScope.msg }
  </span>
</div>
<div class="form">
  <form action="userServlet" method="post">
    <input type="hidden" name="action" value="login" />
    <label>用户名称:</label>
    <input class="itxt" type="text" placeholder="请输入用户名"
           autocomplete="off" tabindex="1" name="username"
           value="${requestScope.username}" />
    <br />
    <br />
    <label>用户密码:</label>
    <input class="itxt" type="password" placeholder="请输入密码"
           autocomplete="off" tabindex="1" name="password" />
    <br />
    <br />
    <input type="submit" value="登录" id="sub_btn" />
  </form>
</div>

在这里插入图片描述

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

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

注册失败页面设置

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

<div class="login_form">
  <div class="login_box">
    <div class="tit">
      <h1>注册会员</h1>
      <span class="errorMsg"></span>
    </div>
    <div class="form">
      <form action="regietServlet" method="post">
        <label>用户名称:</label>
        <input class="itxt" type="text" placeholder="请输入用户名"
               autocomplete="off" tabindex="1" name="username" id="username"/>
        <br/>
        <br/>
        <label>用户密码:</label>
        <input class="itxt" type="password" placeholder="请输入密码"
               autocomplete="off" tabindex="1" name="password" id="password"/>
        <br/>
        <br/>
        <label>确认密码:</label>
        <input class="itxt" type="password" placeholder="确认密码"
               autocomplete="off" tabindex="1" name="repwd" id="repwd"/>
        <br/>
        <br/>
        <label>电子邮件:</label>
        <input class="itxt" type="text" placeholder="请输入邮箱地址"
               autocomplete="off" tabindex="1" name="email" id="email"/>
        <br/>
        <br/>
        <label>验证码:</label>
        <input class="itxt" type="text" name="code" style="width: 150px;" id="code"/>
        <img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px">
        <br/>
        <br/>
        <input type="submit" value="注册" id="sub_btn"/>
      </form>
    </div>
  </div>
</div>

在这里插入图片描述

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

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

对应的registServlet源码如下:

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String code = request.getParameter("code");

        if ("abcd".equalsIgnoreCase(code)) {		// 这里写死code用于测试
            if (userService.existUsername(username)) {
              // 将可以回显的数据写回request域中
                request.setAttribute("msg","该用户名已存在!");
                request.setAttribute("username",username);
                request.setAttribute("email",email);
                request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
            }else {
                userService.login(new User(null, username, password, email));
               // System.out.println("好 注册OK! 正在跳转成功页面·····");
                request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request, response);
            }
        }else {
            request.setAttribute("msg","验证码错误!");
            request.setAttribute("username",username);
            request.setAttribute("email",email);
            request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
        }
    }

对应的jsp页面源码如下

<div class="login_form">
  <div class="login_box">
    <div class="tit">
      <h1>注册会员</h1>
      <span class="errorMsg">
        ${ requestScope.msg }			<!-- 	这里相对于前端页面做了修改。 -->
      </span>
    </div>
    <div class="form">
      <form action="registServlet" method="post">
        <label>用户名称:</label>
        <input class="itxt" type="text" placeholder="请输入用户名"
               value="${requestScope.username}"		
               autocomplete="off" tabindex="1" name="username" id="username"/>
        				<!-- 	这里value值相对于前端页面做了修改。 -->
        <br/>
        <br/>
        <label>用户密码:</label>
        <input class="itxt" type="password" placeholder="请输入密码"
               autocomplete="off" tabindex="1" name="password" id="password"/>
        <br/>
        <br/>
        <label>确认密码:</label>
        <input class="itxt" type="password" placeholder="确认密码"
               autocomplete="off" tabindex="1" name="repwd" id="repwd"/>
        <br/>
        <br/>
        <label>电子邮件:</label>
        <input class="itxt" type="text" placeholder="请输入邮箱地址"
               value="${requestScope.email}"
               autocomplete="off" tabindex="1" name="email" id="email"/>
        				<!-- 	这里email值相对于前端页面做了修改。 -->
        <br/>
        <br/>
        <label>验证码:</label>
        <input class="itxt" type="text" name="code" style="width: 150px;" id="code"/>
        <img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px">
        <br/>
        <br/>
        <input type="submit" value="注册" id="sub_btn"/>
      </form>
    </div>
  </div>
</div>
登陆和注册的页面优化(合并)

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

在这里插入图片描述

jsp页面的更改

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

  • login.jsp:

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

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

在这里插入图片描述

UserServlet页面的更改

public class UserServlet01 extends HttpServlet
{
  private UserService userService = new UserServiceImpl();
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String action = req.getParameter("action");
    if("login".equals(action)){
      login(req,resp);
    }else if("regist".equals(action)){
      regist(req,resp);
    }
  }

  /**
     * 处理登陆请求
     * @param req
     * @param resp
     */
  protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //  1、获取请求的参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    // 调用 userService.login()登录处理业务

    User loginUser = userService.login(new User(null, username, password, null));
    // 如果等于null,说明登录 失败!
    if (loginUser == null) {
      // 把错误信息,和回显的表单项信息,保存到Request域中
      req.setAttribute("msg","用户或密码错误!");
      req.setAttribute("username", username);
      //   跳回登录页面
      req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
    } else {
      // 登录 成功
      //跳到成功页面login_success.html
      req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
    }
  }
  
  /**
     * 处理注册请求
     * @param req
     * @param resp
     */
	protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String email = request.getParameter("email");
    String code = request.getParameter("code");
    System.out.println(code);
    if ("abcd".equalsIgnoreCase(code)) {
      if (userService.existUsername(username)) {
        // System.out.println("存在了!不能注册 正在跳转注册页面·····");
        request.setAttribute("msg","该用户名已存在!");
        request.setAttribute("username",username);
        request.setAttribute("email",email);
        request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
      }else {
        userService.login(new User(null, username, password, email));
        // System.out.println("好 注册OK! 正在跳转成功页面·····");
        request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request, response);
      }
    }else {
      // System.out.println("不争气,,验证码不对!");
      request.setAttribute("msg","验证码错误!");
      request.setAttribute("username",username);
      request.setAttribute("email",email);
      request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
    }
  }
}

使用反射以及BaseServlet优化

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

String action = req.getParameter("action");
if("login".equals(action)){
  login(req,resp);
}else if("regist".equals(action)){
  regist(req,resp);
}

具体过程见如下代码

String action = request.getParameter("action");
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象

Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); // 使用反射获取目标业务名

// 调用目标业务 方法
method.invoke(this, request, response);

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

在这里插入图片描述

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

public abstract class BaseServlet extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request, response);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException  {
    // 解决post请求中文乱码问题
    // 一定要在获取请求参数之前调用才有效
    request.setCharacterEncoding("UTF-8");
    // 解决响应中文乱码
    response.setContentType("text/html; charset=UTF-8");

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

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

bookservlet模块

在这里插入图片描述

UserServlet模块

在这里插入图片描述

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

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

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

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

在这里插入图片描述

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

WebUtils工具类

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

关于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、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");

// 上述四行代码可以用如下一行代码完成替换
User user = WebUtils.copyParamToBean(request.getParameterMap(), new User());
// 这里传递的参数为参数的键值对,原因如上
  • 在上述代码中,即可获得成功注入请求数据的user对象

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

修改登陆页面

<!-- 	不使用EL表达式 -->
<% request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg")%>
<!-- 	使用EL表达式输入错误信息 -->
${ empty requestScope.msg ? "请输入用户名和密码":requestScope.msg }		


<!-- 	使用EL表达式回显用户名 -->
<input class="itxt" type="text" placeholder="请输入用户名"
       autocomplete="off" tabindex="1" name="username"
       value="${requestScope.username}" />

修改注册页面

<!-- 	使用EL表达式输入错误信息 -->
${ requestScope.msg }

<!-- 	使用EL表达式回显用户名 -->
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
       value="${requestScope.username}"
       autocomplete="off" tabindex="1" name="username" id="username"/>

<!-- 	使用EL表达式回显电子邮件 -->
<label>电子邮件:</label>
<input class="itxt" type="text" placeholder="请输入邮箱地址"
       value="${requestScope.email}"
       autocomplete="off" tabindex="1" name="email" id="email"/>
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值