smbms超市订单管理系统(三)_长安也有星星的博客-爱代码爱编程
文章目录
项目资源可以从我的github上获取
https://github.com/chiyu999/smbms.git
三、登录功能优化(注销及权限过滤)
3.1、注销
1、编写servlet
package com.zhang.servlet.user;
import com.zhang.utils.Constants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//移除用户session
req.getSession().removeAttribute(Constants.USER_SESSION);
if (req.getSession().getAttribute(Constants.USER_SESSION) == null){
System.out.println("成功移除用户session,返回登录页面");
}
//返回登录页面
resp.sendRedirect("login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2、注册servlet
<!--退出登录Servlet-->
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>com.zhang.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/logout.do</url-pattern>
</servlet-mapping>
3.2、登录拦截优化
登录成功,然后退出,退出之后发现用链接进去frame.jsp页面也能进去
退出系统后进入的页面
于是要写个登录拦截器去拦截所有请求,如果用户为登录,则不能进入后台页面
1、编写Filter
package com.zhang.filter;
import com.zhang.pojo.User;
import com.zhang.utils.Constants;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SystemFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//过滤器,从session中获取用户
User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);
if (user == null){//用户已经注销或者未登录
resp.sendRedirect("/error.jsp");
}else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
2、注册Filter
<!--登录拦截过滤器-->
<filter>
<filter-name>SystemFilter</filter-name>
<filter-class>com.zhang.filter.SystemFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SystemFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
</filter-mapping>
3、测试
四、密码修改
思路:
- dao:根据传进来的userCode 和 password 执行一条update语句
- service: 根据前端传进来的参数,跟后台的数据进行匹配,调用dao层实现
- servlet : 从前端获取数据,调用service层业务
1、编写UserDao接口
/**
* 修改当前用户密码
* @param connection
* @param id
* @param pwd
* @return int
* @throws Exception
*/
public int updatePwd(Connection connection, int id, String pwd)throws Exception;
2、编写UserDaoImpl实现类
/**
* 修改当前用户密码
* @param connection
* @param id
* @param pwd
* @return int
* @throws Exception
*/
@Override
public int updatePwd(Connection connection, int id, String pwd) throws Exception {
PreparedStatement pstm = null;
int execute = 0;
if (connection != null){
String sql = "update smbms_user set userPassword =? where id = ?";
//接收参数
Object[] params = {pwd,id};
for (int i = 0; i < params.length; i++) {
pstm.setObject(i+1,params[i]);
}
execute = BaseDao.execute(connection, pstm, sql, params);
BaseDao.closeResource(null,pstm,null);
}
return execute;
}
3、编写UserService接口
/**
* 根据userId修改用户密码
* @param id
* @param pwd
* @return boolean
* @throws Exception
*/
public boolean updatePwd(int id, String pwd);
4、编写UserServiceImpl实现类
/**
* 根据用户id修改密码
* @param id
* @param pwd
* @return boolean true==修改成功 false==修改失败
*/
@Override
public boolean updatePwd(int id, String pwd) {
Connection connection = null;
//标志位,用于标志是否修改密码成功
boolean flag = false;
try {
connection = BaseDao.getConnection();
//修改密码
if (userDao.updatePwd(connection, id, pwd)>0){
flag = true;
return flag;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(connection,null,null);
}
return flag;
}
5、编写UserServlet
/**
* 实现Servlet复用
* User的操作都在这个Servlet中实现
*/
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//因为是根据id修改密码,在登录的时候已经把用户的所有信息都存到userSession中了,可以从session中获取当前用户的id
//获取用户
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
//从前端获取新密码
String newpassword = req.getParameter("newpassword");
System.out.println("UserServlet========>"+newpassword);
//设立标志位,默认修改不成功
boolean flag = false;
//判断获取到的用户是否为空,新密码是否为空
if((User)o != null && newpassword != null && newpassword.length()>0){
//调用service层方法实现业务
UserServiceImpl userService = new UserServiceImpl();
//把更新密码的结果设置给flag
System.out.println("UserServlet"+((User) o).getId());
flag = userService.updatePwd(((User) o).getId(), newpassword);
if (flag){ //如果为true,则说明修改密码成功
//密码修改成功,需要重新登录,提示修改密码成功,移除用户session
req.setAttribute("message","密码修改成功,请返回登录页面,使用新密码重新登录");
req.getSession().removeAttribute(Constants.USER_SESSION);
}else {
//密码修改失败
req.setAttribute("message","密码修改失败");
}
}else { //
req.setAttribute("message","新密码有问题");
}
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
这里为了实现Servlet的复用,在前端用了个隐藏域来定义提交的方法,这里需要把这个代码封装成一个方法,在doget里调用那么UserServlet的代码就会重构成下面这样,之后要操作User,则在本类中增加方法,在doget中增加分支即可
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if (method != null && method.equals("savepwd")){
this.updatePwd(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
private void updatePwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//因为是根据id修改密码,在登录的时候已经把用户的所有信息都存到userSession中了,可以从session中获取当前用户的id
//获取用户
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
//从前端获取新密码
String newpassword = req.getParameter("newpassword");
//设立标志位,默认修改不成功
boolean flag = false;
//判断获取到的用户是否为空,新密码是否为空
if((User)o != null && newpassword != null && newpassword.length()>0){
//调用service层方法实现业务
UserServiceImpl userService = new UserServiceImpl();
//把更新密码的结果设置给flag
// System.out.println("UserServlet"+((User) o).getId());
flag = userService.updatePwd(((User) o).getId(), newpassword);
if (flag){ //如果为true,则说明修改密码成功
//密码修改成功,需要重新登录,提示修改密码成功,移除用户session
req.setAttribute("message","密码修改成功,请返回登录页面,使用新密码重新登录");
req.getSession().removeAttribute(Constants.USER_SESSION);
}else {
//密码修改失败
req.setAttribute("message","密码修改失败");
}
}else { //
req.setAttribute("message","新密码有问题");
}
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
}
}
6、测试功能
7、遇到的bug
空指针异常
刚开始在编写dao层代码的时候没有进行测试,才导致到后面修改密码不成功,苦恼好久,愣是粗心没有发现这个问题,原先的代码是这样的
public int updatePwd(Connection connection, int id, String pwd) throws Exception {
PreparedStatement pstm = null;
int execute = 0;
if (connection != null){
String sql = "update smbms_user set userPassword= ? where id = ?";
//接收参数
Object[] params = {pwd,id};
for (int i = 0; i < params.length; i++) {
pstm.setObject(i+1,params[i]);
}
execute = BaseDao.execute(connection, pstm, sql, params);
// System.out.println("更改密码结果=====>"+execute);
BaseDao.closeResource(null,pstm,null);
}
return execute;
}
里面有这么一段代码
for (int i = 0; i < params.length; i++) {
pstm.setObject(i+1,params[i]);
}
这是给预编译sql占位符设置值的,着原本是在BaseDao这个数据连接公共类中做的,结果在这里我给他赋值了一次,导致他报了个空指针异常
解决思路
因为是空指针异常,所以我第一时间想的是哪一个参数会是空的吗?
我是依次从servlet—>service---->dao层打印了各个参数,结果发现参数都没有问题,可是就是会报空指针,也没有执行到sql语句,结果后来叫了舍友过来看了下,说了出来才理清了思路发现了这里给预编译设置值了结果把代码删了过仍然就可以跑的通了
到最后还在想一个问题,数组里的东西:预编译sql的机制是怎样的,到现在都想不通,只是看到了setobject方法的源码,看了excudeUpdate方法找下去,能力不够,看不懂,想不通想不通
五、密码修改功能优化
Ajax 实现旧密码验证
前端代码
$.ajax({
type:"GET",
url:path+"/jsp/user.do",
data:{method:"pwdmodify",oldpassword:oldpassword.val()},
dataType:"json",
success:function(data){
if(data.result == "true"){//旧密码正确
validateTip(oldpassword.next(),{"color":"green"},imgYes,true);
}else if(data.result == "false"){//旧密码输入不正确
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 原密码输入不正确",false);
}else if(data.result == "sessionerror"){//当前用户session过期,请重新登录
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 当前用户session过期,请重新登录",false);
}else if(data.result == "error"){//旧密码输入为空
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请输入旧密码",false);
}
},
error:function(data){
//请求出错
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请求错误",false);
}
});
会走这个请求/jsp/user.do下面的pwdmodify
相当于请求 项目名/jsp/user.do?method=pwdmodify
UserServlet 新增方法
public void getPwdByUserId(HttpServletRequest req, HttpServletResponse resp){
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = req.getParameter("oldpassword");
//万能的Map,一切东西都可以存放
Map<String, String> resultMap = new HashMap<String, String>();
if (o == null){ //Session过期了
resultMap.put("result","sessionerror");
}else if (StringUtils.isNullOrEmpty(oldpassword)){//如果前端获取的参数是null或空串
resultMap.put("result","error");
}else {
String userPassword = ((User) o).getUserPassword();
if (userPassword.equals(oldpassword)){ //旧密码正确
resultMap.put("result","true");
}else { //旧密码错误
resultMap.put("result","false");
}
}
//把Map里的值去除以json格式的字符串返回给前端
//设置返回响应头
resp.setContentType("application/json");
//获取流
PrintWriter outPrintWriter = null;
try {
outPrintWriter = resp.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
//alibab的JSONArray工具类,转换格式使用
//={key,value} 然后传递给前端 result
outPrintWriter.write(JSONArray.toJSONString(resultMap));
outPrintWriter.flush();
outPrintWriter.close();
}
新增分支
else if (method != null && method.equals("pwdmodify")){
this.getPwdByUserId(req, resp);
}