人已经在厦工了,寄😭😭😭
这一阶段,基本都是优化,各种优化捏🤗
🤗1、结合之前所学优化
结合之前所学内容,对之前的book项目进行优化
1.1、页面jsp动态化
1、在html页面顶行添加page指令
2、修改文件后缀名为: .jsp
3、使用IDEA搜索替换.html
为.jsp
单个文件里的内容
CTRL + R
多个文件搜索
CTRL + SHIFT + R
1.2、抽取页面中相同的内容
抽取页面中相同的内容 (❌)
静态包含乱杀 (✔)
1.2.1、head 中css、jquery、 base 标签
我们在src/main/webapp/pages/common/
下创建一个head.jsp
,用来处理代码中重复使用的base标签、css样式、jQuery文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8080/book/">
<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标签 css样式 jQuery文件 --%>
<%@include file="/pages/common/head.jsp"%>
对比图
是不是,非常的简洁😍,来,试试看,按照这样,把整个项目都改改吧!!!
1.2.2、每个页面的页脚
我们还会发现每个页面的底下都有页脚,代码也是完全一样的,所以,我们去src/main/webapp/pages/common/
下创建一个footer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
<span>
尚硅谷书城.Copyright ©2015
</span>
</div>
然后,在使用到这几行代码的地方,替换为静态包含
<%-- 静态包含页脚内容 --%>
<%@include file="/pages/common/footer.jsp"%>
1.2.3、登录成功后的菜单
我们还会发现,下面这几行代码,在整个项目中出现了多次,所以,我们又可以用静态包含😤😤😤
因此,我们在src/main/webapp/pages/common/
下创建一个login_success_menu.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
<a href="../order/order.jsp">我的订单</a>
<a href="../../index.jsp">注销</a>
<a href="../../index.jsp">返回</a>
</div>
然后在所有重复的地方用,替换
<div id="header">
<img class="logo_img" alt="" src="static/img/logo.gif" >
<%-- 静态包含,登入成功的菜单 --%>
<%@include file="/pages/common/login_success_menu.jsp"%>
</div>
1.2.4、manager 模块的菜单
🤔🤔🤔经过,我们仔细的阅读代码,我们还会发现,在manger模块里,有重复的内容可以用静态包含替换,因此,我们在src/main/webapp/pages/common/
下创建一个manager_menu.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<a href="book_manager.jsp">图书管理</a>
<a href="order_manager.jsp">订单管理</a>
<a href="../../index.jsp">返回商城</a>
</div>
然后去替换
<%-- 静态包含manager管理模块的菜单 --%>
<%@include file="/pages/common/manager_menu.jsp"%>
1.3、动态的base标签值
我们一般用localhost去访问服务器,那么现在我们换一个ip去访问。因为,我们的base标签写死了,会出现,
我们ip是192.168.1.6,但是css的url还是loacalhost,因为上面base标签相同,所以jQuery也有这样的问题。
因此,这里我们去src/main/webapp/pages/common/
下的head.jsp
小改1下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// http://localhost:8080/工程路径/
String basePath = request.getScheme()
+ "://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath() //request.getContextPath()返回 /工程路径,所以这里不需要加/
+ "/";
%>
<%= basePath %>
<!--写base标签,永远固定相对路径跳转的结果-->
<base href= <%= 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>
🤗2、表单提交错误回显
图解
登入部分代码实现
具体看最后面的几行代码,如果失败,就把信息存到request域中
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("接收到用户的账为"+username+"\t"+password);
// 2、调用XxxService. xxx()处理业务
// userService. login(登录
User user = userService.login(new User(null, username, password, null));
// 3、根据login()方法返回结果判断登录是否成功
if(!(user == null)) {
// 成功
// 跳到成功页面login_ success. html
System.out.println(username + " 登入成功");
request.getRequestDispatcher("/pages/user/login_success.jsp").forward(request,response);
}else {
// 失败
// 跳回登录页面
//把错误的信息(msg),和回显的表单项信息(username),保存到request域中
request.setAttribute("msg","用户名或密码错误");
request.setAttribute("username",username);
System.out.println(username + " 登入失败");
request.getRequestDispatcher("/pages/user/login.jsp").forward(request,response);
}
}
}
后面我们对login.jsp
的错误信息部分和用户名(value)部分进行修改
...
<span class="errorMsg">
<%= request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg") %>
</span>
...
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username"
value="<%= request.getAttribute("username")==null?"":request.getAttribute("username")%>"/>
注册部分代码实现
主要看后几行的验证码错误,和账号已存在,我们把数据保存到request域中
public class RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
System.out.println("读取的数据为" + username +"\t" + password + "\t" + email + "\t" + code);
// 2、检查验证码是否正确 这里我们先写死abcde
if("abcde".equals(code)) {
// 正确
// 3、检查用户名是否可用
if(!userService.existsUsername(username)) {
// 可用
// 调用Sservice保存到数据库
//userService.registUser(new User(null,username,password,email));
// 跳到注册成功末面regist_success.jsp
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}else {
// 不可用
System.out.println("用户名[ " + username + " ]已存在");
//把回显信息放到request域中
request.setAttribute("msg","用户名已存在");
request.setAttribute("username",username);
request.setAttribute("email",email);
// 跳回注册页面
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}else{
// 验证码不正确
//把回显信息放到request域中
request.setAttribute("msg","验证码输入有误");
request.setAttribute("username",username);
request.setAttribute("email",email);
System.out.println("验证密码[ "+code+" ]错误");
// 跳回注册页面
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}
}
注册的页面regist.jsp
同样这么处理,我们修改错误信息、用户名、电子邮件
...
<span class="errorMsg">
<%= request.getAttribute("msg")==null?"" : request.getAttribute("msg")%>
</span>
...
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username" id="username"
value="<%= request.getAttribute("username")==null?"" : request.getAttribute("username")%>"
/>
...
<label>电子邮件:</label>
<input class="itxt" type="text" placeholder="请输入邮箱地址"
autocomplete="off" tabindex="1" name="email" id="email"
value="<%= request.getAttribute("email")==null?"" : request.getAttribute("email")%>"
/>
🤗3、代码优化
3.1、合并注册和登入代码
在实际的项目开发中,一个模块,一般只用一个servlet程序
登入和注册都属于一个模块(用户模块),结合上图,实现合并🤗
代码实现
我们到regist.jsp页面和login.jsp页面,在其表单中添加隐藏域
<input type="hidden" value="login" name="action"> <%-- login.jsp --%>
<input type="hidden" value="regist" name="action"> <%-- regist.jsp --%>
同时表单的action属性也要改
<form action="userServlet" method="post">
👇下面更是重量级的结合体UserServlet
public class UserServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("接收到用户的账为"+username+"\t"+password);
// 2、调用XxxService. xxx()处理业务
// userService. login(登录
User user = userService.login(new User(null, username, password, null));
// 3、根据login()方法返回结果判断登录是否成功
if(!(user == null)) {
// 成功
// 跳到成功页面login_ success. html
System.out.println(username + " 登入成功");
request.getRequestDispatcher("/pages/user/login_success.jsp").forward(request,response);
}else {
// 失败
// 跳回登录页面
//把错误的信息(msg),和回显的表单项信息(username),保存到request域中
request.setAttribute("msg","用户名或密码错误");
request.setAttribute("username",username);
System.out.println(username + " 登入失败");
request.getRequestDispatcher("/pages/user/login.jsp").forward(request,response);
}
}
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
System.out.println("读取的数据为" + username +"\t" + password + "\t" + email + "\t" + code);
// 2、检查验证码是否正确 这里我们先写死abcde
if("abcde".equals(code)) {
// 正确
// 3、检查用户名是否可用
if(!userService.existsUsername(username)) {
// 可用
// 调用Sservice保存到数据库
//userService.registUser(new User(null,username,password,email));
// 跳到注册成功末面regist_success.jsp
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}else {
// 不可用
System.out.println("用户名[ " + username + " ]已存在");
//把回显信息放到request域中
request.setAttribute("msg","用户名已存在");
request.setAttribute("username",username);
request.setAttribute("email",email);
// 跳回注册页面
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}else{
// 验证码不正确
//把回显信息放到request域中
request.setAttribute("msg","验证码输入有误");
request.setAttribute("username",username);
request.setAttribute("email",email);
System.out.println("验证密码[ "+code+" ]错误");
// 跳回注册页面
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if("login".equals(action)) {
// 登入功能
login(request,response);
}else if("regist".equals(action)){
// 注册功能
regist(request,response);
}
}
}
3.2、使用反射优化大量else if
刚刚,我们用 if 条件判断,对注册和登入功能,进行了区分,但是未来,我们要是往里面加新的功能(添加用户、修改信息、修改密码…),就会非常的麻烦😨 😨 😨
那么我们应该,怎么做呢,其实因为页面传回来的隐藏域的值,和我们要使用的功能的方法同名,我们就可以使用反射来解决🌶😁😁😁
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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();
}
}
下面,我们启动服务器,进入login.jsp(登入界面)进行debug,我们可以看👀到,已经反射出了我们的注册方法
3.3 BaseServlet优化
刚刚,我们优化了用户模块的代码,那么,我们一想🤔🤔🤔🤔,嗨呀🤗,其他模块,也是这样的优化方式,那我们可以写一个BaseServlet,来减少重复的代码
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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();
}
}
}
原来的UserServlet不继承HttpServlet,只需要继承BaseServlet就行了😍😍😍
public class UserServlet extends BaseServlet {...}
🤗4、BeanUtils工具类
4.1、BeanUtils简单介绍
我们会发现,自己new一个 bean再setXxx()太累了,所以我们要解放自己我😤
BeanUtils工具类,它可以一次性的把所有请求的参数注入到JavaBean中😍
BeanUtils它不是Jdk的类。而是第三方的工具类。所以需要导包😍
导入需要的jar包:
commons-beanutils-1.8.0.jar
commons-logging 1.1.1.jar
4.2、使用BeanUtils类方法实现注入
try {
User user = new User();
System.out.println("注入之前: " + user);
// 把所有请求的参数都注入到user对象中
BeanUtils.populate(user,request.getParameterMap());
System.out.println("注入之后: " + user);
} catch (Exception e) {
e.printStackTrace();
}
4.3、优化BeanUtils
那么,每个方法都这么写就很麻烦了,所以我们可以写一个工具类,要用的时候,直接一行调用😁,所以我们写一个WebUtils
public class WebUtils {
public static void copyParamToBean(HttpServletRequest request, Object bean){
try {
User user = new User();
System.out.println("注入之前: " + bean);
// 把所有请求的参数都注入到user对象中
BeanUtils.populate(bean,request.getParameterMap());
System.out.println("注入之后: " + bean);
} catch (Exception e) {
e.printStackTrace();
}
}
}
但是这么写,耦合性还是太高了,我们把copyParamToBean()方法的参数HttpServletRequest request
改成 Map map
,为什么这么做捏?🤗,原来是,javaEE的三层结构 : Dao 层、Service 层、Web 层,如果函数的参数写成HttpServletRequest request
,Dao层和Service层就用不了了,但时Map,这三层都能用。
还有,这里写成泛型,会使得代码只写一行,不用强转成User(类),更为整洁,所以这样更好😍
User user = WebUtils.copyParamToBean(request.getParameterMap(),new User()); //一行调用
public class WebUtils {
public static <T> T copyParamToBean(Map map, T bean){
try {
User user = new User();
System.out.println("注入之前: " + bean);
// 把所有请求的参数都注入到user对象中
BeanUtils.populate(bean,map);
System.out.println("注入之后: " + bean);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
4.4、BeanUtils根据SetXxx() 方法实现注入
我们找到User类,把其中的SetPassword()去掉,这时,我们可以看到,密码没有值注入进去
下面是尚硅谷书城项目第四阶段
🤗5、用EL表达式修改表单回显
之前我们写的JSP做回显,不太好看,所以这里我们用EL表达式优化
登入页面
<%= request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg") %>
可以改成
${empty requestScope.msg ? "请输入用户名和密码" : requestScope.msg}
username也这样改
value="<%= request.getAttribute("username")==null?"":request.getAttribute("username")%>"
<%-- 改为 --%>
value="${requestScope.username}"
之前的EL表达式学习笔记里,有说过,EL表达式没有找到对应的值,就会输出空串,所以我们可以直接这样写。
注册页面
<span class="errorMsg">
<%-- <%= request.getAttribute("msg")==null?"" : request.getAttribute("msg")%>--%>
${requestScope.msg}
</span>
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username" id="username"
value="${requestScope.username}"
/>
<label>电子邮件:</label>
<input class="itxt" type="text" placeholder="请输入邮箱地址"
autocomplete="off" tabindex="1" name="email" id="email"
value="${requestScope.email}"
/>
新的学期,你准备好了吗?😁,扣1进入新学期