十二 JavaWeb综合案例
12.1 用户管理与DML操作
12.1.1 用户列表
开发步骤
获取用户列表放到首页完成
登录状态才需要获取用户列表
- UserDao
@Override
public List<User> selectUserList() throws Exception {
return new QueryRunner(JDBCUtil.getDataSource())
.query("select * from tb_user",
new BeanListHandler<User>(User.class));
}
- ShowIndexSerlvet
@WebServlet(name = "ShowIndexServlet" ,urlPatterns = "/showIndex")
public class ShowIndexServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User existUser = (User) request.getSession().getAttribute("existUser");
StringBuffer responseBody = new StringBuffer();
if (null != existUser) {
//已经在登录状态
responseBody.append("欢迎回来~ " + existUser.getUsername());
responseBody.append(" <a href='/day60/logout'>注销</a><br>");
//获取用户列表
UserDao userDao = new UserDaoImpl();
try {
List<User> userList = userDao.selectUserList();
System.out.println(userList);
responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");
responseBody.append("<tr>");
responseBody.append("<td>ID</td>");
responseBody.append("<td>账户</td>");
responseBody.append("<td>密码</td>");
responseBody.append("</tr>");
for (User user : userList) {
//遍历一个User对象,对应就应该有一个tr
responseBody.append("<tr>");
responseBody.append("<td>"+user.getId()+"</td>");
responseBody.append("<td>"+user.getUsername()+"</td>");
responseBody.append("<td>"+user.getPassword()+"</td>");
responseBody.append("</tr>");
}
responseBody.append("</table>");
} catch (Exception e) {
e.printStackTrace();
}
} else {
//不在登录状态
responseBody.append("您还没有登录,<a href='/day60/login.html'>请登录</a><br>");
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(responseBody.toString());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
12.1.2 删除用户
开发步骤
首页,给每一个记录后面添加一个删除按钮
用户列表不要显示当前登录用户
- UserDao
@Override
public void deleteUserById(Integer id) throws Exception {
new QueryRunner(JDBCUtil.getDataSource())
.update("delete from tb_user where id = ?",id);
}
- ShowIndexServlet
responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");
responseBody.append("<tr>");
responseBody.append("<td>ID</td>");
responseBody.append("<td>账户</td>");
responseBody.append("<td>密码</td>");
responseBody.append("<td>操作</td>");
responseBody.append("</tr>");
for (User user : userList) {
if ( user.getId() != existUser.getId()) {
//遍历一个User对象,对应就应该有一个tr
responseBody.append("<tr>");
responseBody.append("<td>"+user.getId()+"</td>");
responseBody.append("<td>"+user.getUsername()+"</td>");
responseBody.append("<td>"+user.getPassword()+"</td>");
responseBody.append("<td><a href='/day60/deleteUser?id="+user.getId()+"'>删除</a></td>");
responseBody.append("</tr>");
}
}
responseBody.append("</table>");
- DeleteUserServlet
@WebServlet(name = "DeleteUserServlet" ,urlPatterns = "/deleteUser")
public class DeleteUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String idStr = request.getParameter("id");
Integer id = Integer.parseInt(idStr);
UserDao userDao = new UserDaoImpl();
try {
userDao.deleteUserById(id);
} catch (Exception e) {
e.printStackTrace();
}
response.sendRedirect("/day60/showIndex");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
12.1.3 批量删除
开发流程
在首页需要给每一个记录新加多选框
当点击批量删除按钮之后,完成批量删除操作
- UserDao
public void deleteUsersByIds(List<Integer> idList) throws Exception {
for (Integer id : idList) {
deleteUserById(id);
}
}
- ShowIndexServlet
responseBody.append("<form action='/day60/deleteUsers' method='post'>");
responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");
responseBody.append("<tr>");
responseBody.append("<td></td>");
responseBody.append("<td>ID</td>");
responseBody.append("<td>账户</td>");
responseBody.append("<td>密码</td>");
responseBody.append("<td>操作</td>");
responseBody.append("</tr>");
for (User user : userList) {
if ( user.getId() != existUser.getId()) {
//遍历一个User对象,对应就应该有一个tr
responseBody.append("<tr>");
responseBody.append("<td><input name='ids' type='checkbox' value='"+user.getId()+"'></td>");
......
responseBody.append("</tr>");
}
}
responseBody.append("</table>");
responseBody.append("<button type='submit'>批量删除</button>");
responseBody.append("</form>");
12.1.4 添加用户
开发步骤
首页加入一个添加用户按钮
点击添加用户按钮进入到登录页面
- UserDao
public void addUser(User inputUser) throws Exception {
new QueryRunner(JDBCUtil.getDataSource())
.update("insert into tb_user(username ,password) values(?,?)",
inputUser.getUsername(),
inputUser.getPassword());
}
- ShowIndexServlet
//已经在登录状态
responseBody.append("欢迎回来~ " + existUser.getUsername());
responseBody.append(" <a href='/day60/logout'>注销</a><br>");
responseBody.append("<a href='/day60/add.html'>添加用户</a><br>");
- AddUserServlet
@WebServlet(name = "AddUserServlet" ,urlPatterns = "/addUser")
public class AddUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User inputUser = new User();
inputUser.setUsername(username);
inputUser.setPassword(password);
//方式一:在添加之前,校验下用户名是否存在
//方式二:让username字段有唯一约束!
UserDao userDao = new UserDaoImpl();
try {
userDao.addUser(inputUser);
//添加成功,跳转到首页
response.sendRedirect("/day60/showIndex");
} catch (Exception e) {
e.printStackTrace();
//添加失败,跳转到添加用户页面
response.sendRedirect("/day60/add.html");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
12.1.5 修改用户
开发步骤
首页加入修改按钮
- UserDao
@Override
public void updateUser(User user) throws Exception {
new QueryRunner(JDBCUtil.getDataSource())
.update("update tb_user set username = ? , password = ? where id = ?",
user.getUsername(),
user.getPassword(),
user.getId());
}
- ShowIndexServlet
for (User user : userList) {
if ( user.getId() != existUser.getId()) {
//遍历一个User对象,对应就应该有一个tr
responseBody.append("<tr>");
responseBody.append("<td><input name='ids' type='checkbox' value='"+user.getId()+"'></td>");
responseBody.append("<td>"+user.getId()+"</td>");
responseBody.append("<td>"+user.getUsername()+"</td>");
responseBody.append("<td>"+user.getPassword()+"</td>");
responseBody.append("<td>" +
"<a href='/day60/deleteUser?id="+user.getId()+"'>删除</a> " +
"<a href='/day60/showUpdateUser?id="+user.getId()+"'>修改</a>"+
"</td>");
responseBody.append("</tr>");
}
}
- ShowUpdateUserServlet 显示修改用户页面
@WebServlet(name = "ShowUpdateUserServlet" , urlPatterns = "/showUpdateUser")
public class ShowUpdateUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer id = Integer.parseInt(request.getParameter("id"));
//根据id查询用户
UserDao userDao = new UserDaoImpl();
StringBuffer responseBody = new StringBuffer();
try {
User user = userDao.selectUserById(id);
System.out.println(user);
responseBody.append("<form action='/day60/updateUser' method='post'>");
responseBody.append("<input type='hidden' name='id' value='"+user.getId()+"'/>");
responseBody.append("账户:<input type='text' name='username' value='"+user.getUsername()+"'/><br>");
responseBody.append("密码:<input type='text' name='password' value='"+user.getPassword()+"'/><br>");
responseBody.append("<button type='submit'>修改</button>");
responseBody.append("</form>");
} catch (Exception e) {
e.printStackTrace();
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(responseBody.toString());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
- UpdateUserServlet 修改用户
@WebServlet(name = "UpdateUserServlet" ,urlPatterns = "/updateUser")
public class UpdateUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer id = Integer.parseInt(request.getParameter("id"));
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username : " + username + ", password : " + password);
//要修改的内容:username、password
User user = new User(id,username,password);
UserDao userDao = new UserDaoImpl();
try {
userDao.updateUser(user);
//修改成功,跳转到首页
response.sendRedirect("/day60/showIndex");
} catch (Exception e) {
e.printStackTrace();
//修改失败,跳转到修改页面
response.sendRedirect("/day60/showUpdateUser?id="+id);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
12.2 BaseServlet优化案例
12.2.1 BaseServlet 的作用
让一个Servlet可以处理多种不同的请求,不同的请求调用Servlet的不同方法。
12.2.2 实现原理
客户端发送请求时, 必须多给出一个参数, 用来说明要调用的方法。这样,BaseServlet 通过该参数来
调用目标方法。
请求处理方法的签名必须与 service 相同, 即方法的返回值和参数,以及声明的异常都相同。
12.2.3 BaseServlet的应用
@WebServlet(name = "UserServlet",urlPatterns = "/user")
public class UserServlet extends BaseServlet {
public void login(HttpServletRequest request,HttpServletResponse response){
String username = request.getParameter("username");
String password = request.getParameter("password");
User inputUser = new User();
inputUser.setUsername(username);
inputUser.setPassword(password);
UserDao userDao = new UserDaoImpl();
try {
User existUser = userDao.login(inputUser);
if (null == existUser) {
//登录失败
request.getRequestDispatcher("/login.html").forward(request,response);
} else {
//登录成功
request.getSession().setAttribute("existUser",existUser);
response.sendRedirect("/day61/user?methodName=showIndex");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void showIndex(HttpServletRequest request , HttpServletResponse response) throws Exception {
System.out.println("showIndex");
User existUser = (User) request.getSession().getAttribute("existUser");
StringBuffer responseBody = new StringBuffer();
if (null != existUser) {
//在登录状态
responseBody.append("欢迎回来~~~"+existUser.getUsername());
responseBody.append("<a href='/day61/user?methodName=logout'>注销登录</a>");
} else {
//不在登录状态
responseBody.append("您还没有登录;");
responseBody.append("<a href='/day61/login.html'>请登录</a>");
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(responseBody.toString());
}
public void logout(HttpServletRequest request , HttpServletResponse response) throws Exception {
request.getSession().invalidate();
response.sendRedirect("/day61/login.html");
}
}
12.2.4 BaseServlet的优化
资源跳转问题
响应正文中文乱码
@WebServlet(name = "BaseServlet",urlPatterns = "/base")
public class BaseServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String methodName = request.getParameter("methodName");
try {
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
if (null != method) {
//处理返回值,为了资源跳转
String returnValue = (String) method.invoke(this,request,response);
System.out.println(returnValue);
//有的方法有返回值
//登录成功:重定向 redirect:/day61/user?methodName=showIndex
//登录失败: 请求转发 forward:/login.html
//有的方法没有返回值
//null,不用做任何处理
if (returnValue != null){
//有返回值,实现资源跳转,需要资源的路径
if (returnValue.lastIndexOf(":") != -1) {
String path = returnValue.split(":")[1];
System.out.println("path : "+path);
//有":"
//实现资源跳转:重定向、请求转发
if (returnValue.startsWith("redirect")) {
//重定向
response.sendRedirect(request.getContextPath()+path);
} else if(returnValue.startsWith("forward")){
//请求转发
request.getRequestDispatcher(path).forward(request,response);
}
} else {
//没有":",默认就是转发 /login.html
request.getRequestDispatcher(returnValue).forward(request,response);
}
} else {
//不做任何处理
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
12.3 jsp优化登录案例
之前方案
login.html
登录页面
LoginServlet
处理登录请求
业务处理
调用dao,操作数据
ShowIndexServlet(java代码)
显示用户名
存在的问题
login.html
无法和java后台进行交互,无法显示错误信息
ShowIndexServlet
html无法和java后台进行交互,java代码应该专注于后台代码
现在方案
login.jsp
登录页面
显示错误信息
LoginServlet
处理登录请求
业务处理
调用dao,操作数据
index.jsp
显示用户名
- login.jsp
<%--显示错误信息--%>
<%="<font color='red'>" + (request.getAttribute("errorMsg") == null ? "" : request.getAttribute("errorMsg") ) + "</font>"%>
<form action="/day62/user" method="post">
<input type="hidden" name="methodName" value="login"/>
账户:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
<button type="submit">登录</button>
</form>
- index.jsp
<%
String username = (String) session.getAttribute("username");
if (null == username) {
//不在登录状态
out.write("您还没有登录;");
out.write("<a href='/day62/login.jsp'>请登录</a>");
} else {
//在登录状态
out.write("欢迎回来~~~"+username);
}
%>
存在的问题
jsp页面还存在java代码(后台代码)和html代码(前端代码)融合在一起的问题!
一定程度解决,可能需要jstl标签库。
彻底解决,得使用vue + html
12.4 三层结构优化
12.4.1 准备工作
环境准备
tomcat8.5
idea2020.1
jdk1.8
导入jar包
BeanUtils
DbUtils
c3p0
mysql驱动
jstl
12.4.2 登录
开发流程
UserServlet
login方法 调用UserService的login方法
UserService
login方法,返回User对象 调用UserDao的login方法
UserDao
login方法,返回User对象 操作数据库,并将记录封装到User对象
登录成功
修改登录状态,重定向到首页
登录失败
记录错误信息,请求转发到登录页面
- UserDao
@Override
public User login(User inputUser) throws Exception {
return new QueryRunner(JDBCUtils.getDataSource())
.query("select * from tb_user where username = ? and password = ?",
new BeanHandler<User>(User.class),
inputUser.getUsername(),
inputUser.getPassword());
}
- UserService
@Override
public User login(User inputUser) throws Exception {
UserDao userDao = new UserDaoImpl();
return userDao.login(inputUser);
}
- UserServlet类的login方法
private UserService userService = new UserServiceImpl();
public String login(HttpServletRequest request,HttpServletResponse response){
User inputUser = new User();
//将请求参数封装到inputUser中
try {
BeanUtils.populate(inputUser,request.getParameterMap());
User existUser = userService.login(inputUser);
//没有异常有返回值
if (null != existUser) {
//登录成功 , 修改登录状态,跳转到首页
request.getSession().setAttribute("existUser",existUser);
return "redirect:/index.jsp";
} else {
//登录失败 ,记录错误信息,跳转到登录页面
request.setAttribute("errorMsg","账户或密码错误");
return "/login.jsp";
}
} catch (Exception e) {
e.printStackTrace();
}
//有异常,应该有返回值 。意味着登录失败,返回登录页面,重新登录
return "/login.jsp";
}
- login.jsp
<body>
<font color="red">${errorMsg}</font>
<form action="${pageContext.request.contextPath}/user" method="post">
<input type="hidden" name="methodName" value="login"/>
账户:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
<button type="submit">登录</button>
</form>
</body>
- index.jsp
<body>
<%--
在登录状态
显示用户名
--%>
<c:if test="${existUser != null}">
欢迎回来~~~ ${existUser.username} <a href="${pageContext.request.contextPath}/user?methodName=logout">注销</a>
</c:if>
<%--
不在登录状态
提示登录
--%>
<c:if test="${existUser == null}">
您还没有登录,<a href="${pageContext.request.contextPath}/login.jsp">请登录</a>
</c:if>
</body>
12.4.3 注销登录
开发步骤
login.jsp上需要加一个“注销”的按钮
注销成功 跳转到登录页面
注销失败 跳转到首页,重新进行手动注销
- UserServlet
public String logout(HttpServletRequest request,HttpServletResponse response){
try {
request.getSession().invalidate();
return "redirect:/login.jsp";
} catch (Exception e) {
e.printStackTrace();
return "/index.jsp";
}
}
12.4.4 用户列表
开发步骤
登录成功,重定向到UserServlet中的selectUserList方法
在selectUserList方法中获取用户列表,并将其保存
再请求转发到index.jsp
- UserDao
@Override
public List<User> selectUserList() throws Exception {
return new QueryRunner(JDBCUtils.getDataSource())
.query("select * from tb_user",
new BeanListHandler<User>(User.class));
}
- UserServlet类的selectUserList方法
public String selectUserList(HttpServletRequest request,HttpServletResponse response) throws Exception {
List<User> userList = userService.selectUserList();
request.getSession().setAttribute("userList",userList);
return "/index.jsp";
}
- index.jsp
<body>
<%--
在登录状态
显示用户名
--%>
<c:if test="${existUser != null}">
欢迎回来~~~ ${existUser.username} <a href="${pageContext.request.contextPath}/user?methodName=logout">注销</a>
<%--显示用户列表--%>
<table border="1px" cellspacing="0px" cellpadding="15px" width="500px" height="200px">
<tr>
<td>ID</td>
<td>账户</td>
<td>密码</td>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
</tr>
</c:forEach>
</table>
</c:if>
<%--
不在登录状态
提示登录
--%>
<c:if test="${existUser == null}">
您还没有登录,<a href="${pageContext.request.contextPath}/login.jsp">请登录</a>
</c:if>
</body>
12.4.5 登录校验
需求:只要不在登录状态就自动跳转到登录页面
开发步骤
定义过滤器
判断是否和登录相关
和登录相关,直接放行
访问登录页面
处理登录,请求参数methodName="login"
和登录无关,进行登录状态判断
不在登录状态,跳转到login.jsp
在登录状态,直接放行
- filter.LoginFilter
@WebFilter(filterName = "LoginFilter" ,urlPatterns = "/*")
public class LoginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("LoginFilter doFilter");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//登录校验
String requestURI = request.getRequestURI();
String methodName = request.getParameter("methodName");
if (requestURI.contains("login") || ( methodName != null && methodName.equals("login"))) {
//和登录相关的资源,直接放行
chain.doFilter(req, resp);
} else {
//和登录无关的资源
Object existUser = request.getSession().getAttribute("existUser");
if (null == existUser) {
//不在登录状态,跳转到login.jsp
response.sendRedirect("/day64/login.jsp");
} else {
//在登录状态,直接放行
chain.doFilter(req, resp);
}
}
}
public void init(FilterConfig config) throws ServletException {
}
}
12.4.6 删除用户
开发步骤
给table每一行加删除按钮
不管是删除成功,还是删除失败,都应该重新获取用户列表并显示
转发到UserServlet类的selectUserList方法
- index.jsp
......
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>
<a href="${pageContext.request.contextPath}/user?methodName=deleteUserById&id=${user.id}">删除</a>
</td>
</tr>
</c:forEach>
......
- UserDao
@Override
public int deleteUserById(Integer id) throws Exception {
return new QueryRunner(JDBCUtils.getDataSource())
.update("delete from tb_user where id = ?",
id);
}
- UserService
@Override
public boolean deleteUserById(Integer id) throws Exception {
return userDao.deleteUserById(id) == 1;
}
- UserServlet的deleteUserById方法
public String deleteUserById(HttpServletRequest request,HttpServletResponse response){
Integer id = Integer.parseInt(request.getParameter("id"));
try {
boolean flag = userService.deleteUserById(id);
} catch (Exception e) {
e.printStackTrace();
}
//获取用户列表
return "/user?methodName=selectUserList";
}
12.4.7 修改用户
开发步骤
在table的每一行中加修改按钮
当点击table中修改按钮,跳转到UserServlet类中的toUpdateUserById方法
UserServlet类中的toUpdateUserById方法
获取用户信息
跳转到修改用户页面
当点击修改页面中的修改按钮,开始修改
修改成功,跳转到UserServlet类中的selectUserList方法
修改失败,跳转到toUpdateUserById方法,让它重新进行修改用户
- UserDao
@Override
public void updateUserById(User inputUser) throws Exception {
new QueryRunner(JDBCUtils.getDataSource())
.update("update tb_user set username = ? , password = ? where id = ?",
inputUser.getUsername(),
inputUser.getPassword(),
inputUser.getId());
}
- UserServlet类toUpdateUserById方法
public String toUpdateUserById(HttpServletRequest request,HttpServletResponse response) {
Integer id = Integer.parseInt(request.getParameter("id"));
User user = null;
try {
user = userService.selectUserById(id);
} catch (Exception e) {
e.printStackTrace();
}
request.setAttribute("user",user);
return "/updateUser.jsp";
}
- updateUser.jsp
<body>
<font color="red">${errorMsg}</font>
<form action="${pageContext.request.contextPath}/user" method="post">
<input type="hidden" name="methodName" value="updateUserById"/>
<input type="hidden" name="id" value="${user.id}">
账户:<input type="text" name="username" value="${user.username}"><br>
密码:<input type="text" name="password" value="${user.password}"><br>
<button type="submit">修改</button>
</form>
</body>
- UserServlet类updateUserById方法
public String updateUserById(HttpServletRequest request,HttpServletResponse response){
User inputUser = new User();
try {
BeanUtils.populate(inputUser,request.getParameterMap());
userService.updateUserById(inputUser);
//修改成功
return "/user?methodName=selectUserList";
} catch (Exception e) {
e.printStackTrace();
}
request.setAttribute("errorMsg","修改失败");
//修改失败
return "/user?methodName=toUpdateUserById&id="+inputUser.getId();
}