博客项目准备 + 用户模块
简单实现 博客项目
具体功能
1、增删改查
2、免登录: cookie 与 session
3、非法登录: 过滤器
4、分页:
5、ajax: 操作表格
6、文件上传
7、富文本编辑器
技术运用
1、jsp&servlet
2、jquery 及插件
3、UEditor
4、log4j
5、junit
开发环境
Eclipse + mysql + window + jdk1.8 + tomcat8
注意: tomcat8 字符集为 utf-8 (get | tomcat7 以下) POST 所有的服务都需要处理
流程
调研 需求分析 规格分析 前端 后端 测试 实施 需求变更
环境搭建 及 准备
1、配置 JDK
Window —> preferences (参数选择) —> java —> installed JRES
—> Add —>Standard VM (标准 Java 虚拟器设置)—> 找到对应的 JDK
2、配置 Tomcat
Window —> preferences —> Server —> Runtime Environments
(运行环境) —> Add —> Apache —> 选择 Apache Tomcat v8.0
—> 找到 tomcat 路径以及设置对应的 jdk
软件准备
1、新建项目
2、更改 JSP 字符集
3、更改 JSP 模板
4、新建登录页面
1)、拷贝登录的静态资源
建立文件夹放入 css js 图片 以及 UE、SweetAlert、bs3。
拷贝 login.html 到 login.jsp 中。
2)、修改静态文件引入路径
5、新建主页页面
1)、拷贝 note.css 到 statics/css 中
2)、新建 bootstrap3 拷贝 所有的 bs 的资源
3)、修改 html 中引入路径
4)、提取模板
可变的内容 放入到 其他的 jsp ,使用 jsp:include 导入
6、其他页面
1)、用户页面
User/info.jsp
2)、类型页面
Notetype/list.jsp
.............................
.............................待补充
.............................
.............................
具体步骤
准备工作
===========================分层思想===========================
分层思想
Servlet/Web层:
1、接收请求
2、调用Service层的方法,得到返回结果
3、响应结果给客户端
Service层:
1、业务逻辑判断
3、调用Dao层的方法,得到返回结果
4、将处理好的请求返回给web层
Dao层:
JDBC操作
数据库的增删改查
===========================单元测试===========================
项目右键 new ==> JUnit Test Case
单元测试
1、不能有父类
2、不能是静态方法
3、不能有参数
4、返回值是void
方法上需要设置注解@Test
===========================日志的使用==========================
日志
1、将日志的所需要的jar包拷贝到项目的lib目录下
log4j-1.2.17.jar、
api-1.7.12.jar、
slf4j-log4j12-1.7.12.jar
2、准备配置文件
log4j.properties
a、设置日志输出目的地
b、设置日志的级别
3、使用日志
a、使用日志工厂类
private static Logger logger = LoggerFactory.getLogger(类名.class);
b、使用
logger.info("日志内容....");
logger.info("日志内容{}","这里的内容是填充{}占位符的");
日志代码示例:
log4j.properties
使用方法:
private static Logger logger = LoggerFactory.getLogger(类名.class);
在要使用的类中填入
filter过滤器
乱码过滤器
com.gy.filter.EncodeFilter
自动登录过滤器
com.gy.filter.LoginAccessFilter.java
Utils工具类
DBUtil
数据库工具类
1、打开数据库连接
2、关闭资源
json工具类JsonUtil
字符串 ==> json字符串
将对象转换成JSON字符串,并响应给ajax的回调函数
密码加密工具类MD5Util
密码加密
字符串工具类StringUtil
String判断
用户模块
===========================功能思路===========================
用户行为 actionName
用户登录 actionName=login
用户退出 actionName=logout
进入个人中心 actionName=userCenter
加载头像 actionName=userHead
验证昵称的唯一性 actionName=checkNick
修改用户信息(上传文件) actionName=updateInfo
一、用户登录
前台:
表单实现登录
1、姓名文本框、密码框、复选框(记住密码)、登录按钮、隐藏域(设置actionName)
2、表单元素设置name属性值
3、表单验证
1、得到文本框和密码框的值
2、参数的非空判断
如果为空,不提交表单,提示信息
3、如果参数不为空,提交表单
后台:
整体思路:
1、接收参数
2、判断参数是否为空
如果为空,将错误原因设置到reqeust作用域中,请求转发跳转到登录页面,并return
3、通过用户名查询用户对象是否存在
如果不存在,将错误原因设置到reqeust作用域中,请求转发跳转到登录页面,并return
4、如果存在,将数据库中的密码与前台传递的密码作比较
如果不正确,将错误原因设置到reqeust作用域中,请求转发跳转到登录页面,并return
5、如果正确,登录成功
1、将用户对象存到session作用域中
2、判断用户是否选择记住密码
如记住,则存cookie对象
3、重定向跳转到indexServlet
Servelt层(登录):(接收请求、响应结果)
1、接收参数
2、调用Service层的方法,得到resultInfo对象
3、判断resultInfo的code的值,判断是否登录成功
如果失败,将resultInfo对象存到request作用域中,请求转发跳转到登录页面
如果成功
1、将用户对象存到session作用域中
2、判断用户是否选择记住密码
如记住,,则存cookie对象
3、重定向跳转到indexServlet
Service层(登录):(业务逻辑)
1、判断参数是否为空
如果为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
2、调用Dao层的查询方法,通过用户名查询用户对象,返回用户对象
如果用户对象为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
3、如果存在,将数据库中的密码与前台传递的密码作比较
如果不正确,设置resultInfo对象的code和msg的值,
如果正确,设置resultInfo的code=1,
4、返回resultInfo给servlet层
Dao层(登录):
1、定义sql语句
"select * from tb_user where uname = ? "
2、参数集合
3、调用BaseDao () ==> 单个user对象
原生方法:(1、通过用户名查询用户对象是否存在
1、得到数据库连接
2、定义sql语句
3、预编译
4、设置参数,下标从1开始
5、执行查询,返回结果集
6、判断并分析结果集,得到用户对象
7、关闭资源
8、返回用户对象)
二、非法访问拦截、自动登录
LoginAccessFilter拦截
非法访问拦截
拦截什么:拦截所有资源路径
拦截到哪里:login.jsp
什么资源路径该放行:
1、指定页面,放行 (无需登录即可访问的页面需要放行,如登录、注册等页面)
2、静态资源,放行 (js、css、images等静态资源需要放行,项目中statics目录下的资源都放行)
3、指定行为,放行 (无需登录即可执行的操作需要放行,如登录操作、注册操作等)
4、登录状态,放行 (判断session中的user对象是否为空;不为空则为登录状态)
自动登录
前提:
1、非登录状态
2、有cookie对象
思路:
写在判断session中的user对象是否存在的条件之后 (非登录状态)
1、获取cookie数组
2、判断cookie数组是否为空
3、如果不为空,遍历cookie数组
4、得到指定名称的cookie对象中的name和value
5、分别得到value中的用户名和密码
6、请求转发跳转到登录操作
三、进入个人中心
顺序流程会进入 ==> IndexServlet
前台:
设置"个人中心"的超链接的访问地址为
userServlet?actionName=userCenter
(为了在主页点击 个人中心而进行刷新)
后台:
Servlet层(个人中心)
(对应在主页面点击个人中心)
1、设置首页动态包含的页面值
2、请求转发跳转到index.jsp
IndexServlet 主页
(对应从登录页面登录成功进入个人中心)
1、设置首页动态包含的页面值
2、请求转发跳转到index.jsp
四、加载头像
前台:
设置img标签的src属性: userServlet?actionName=userHead&imageName=${user.head}(图片名从session域对象中获取)
后台:
头像中的链接是启动项(userServlet?actionName=userHead......)
servlet层(加载头像)
1、得到参数(图片名)
2、得到图片的存放路径getServletContext().getRealPath()
(提前建好文件夹)
3、通过路径,得到file对象(参数拼接)
4、判断file对象是否存在,并且是一个标准文件
5、得到图片的后缀
6、根据不同的后缀设置对应的响应类型
7、将文件对象通过工具类FileUtils.copyFile()响应给客户端
注:FileUtils.copyFile()需要拷贝jar包 :commons-io.jar
五、用户退出
前台:
超链接传到后台"userServlet?actionName=logout"
后台:
servlet层(用户退出)
1、销毁session(.invalidate()方法)
2、删除cookie(cookie时间设为0)
3、跳转到登录页面 (重定向)
六、验证昵称的唯一性
前台:
这里没做mood(心情)的处理只是获取而已
JS获取域对象中的值(需要加引号)获取旧昵称的值时使用
'${key}' 以防键误解(可能取值时报错) ==> 步骤3
昵称文本框绑定失焦事件.blur
1、得到昵称文本框的值
2、非空判断
如果为空,提示 禁用按钮 且return
3、判断值是否做了改变
如果没做改变,直接return
4、如果值发生改变
发送ajax请求,判断昵称是否可用
响应1或0,1=可用;0=不可用
如果可用,清空提示信息,按钮可用
如果不可用,提示用户,且禁用按钮
昵称文本框绑定聚焦事件
清空提示信息,按钮可用
后台:
Servlet层:(昵称唯一)
1、接收参数 昵称
2、从session域对象中得到用户对象,从而得到用户ID
3、调用Service层的防范,返回结果 (0或1)
4、通过输出流响应结果(需要将数值转成字符串)
Service层:(昵称唯一)
1、判断参数是否为空
如果为空,返回0
2、调用Dao层,通过昵称和用户ID查询数据库中除了当前记录之后是否有其他记录使用该昵称,返回user对象
3、判断user对象是否为空
如果为空,返回1
如果不为空,返回0
Dao层:(昵称唯一)
通过昵称和用户ID查询数据库中除了当前记录之后是否有其他记录使用该昵称,返回user对象 (单个对象)
"select * from tb_user where nick = ? and userId != ?"
七、修改用户信息
前台:
文件上传表单
提交方式 method="POST"
enctype="multipart/form-data"
表单元素设置name属性值
后台:
注:需要在Servlet上加注解 @MultipartConfig
Servlet层:(修改用户信息)
1、调用Service层的方法,返回resultInfo对象
2、将resultInfo对象存到request作用域中
3、请求转发跳转到个人中心 userServlet?actionName=userCneter
Service层:(修改用户信息)
1、接收参数 (昵称、心情)
2、参数非空判断 (昵称)
3、从session作用域中得到user对象,得到用户ID
4、判断昵称的唯一性
4、===实现文件上传====
1、得到Part对象 request.getPart("name") "name"代表的是前台的file文件域的name属性值
2、得到上传的文件名
3、判断文件名是否不为空
如果为空,表示未上传文件
如果不为空,则得到文件要存放的地址
4、上传文件到指定路径
5、如果上传了文件,则修改用户头像,否则使用原来的头像
6、调用Dao层的修改方法,返回受影响的行数
7、判断受影响的行数
如果大于0,成功,更新session作用域中色user对象
如果不大于0,失败
Dao层:(修改用户信息)
通过用户ID修改用户对象
代码段
com.gy.web(接收响应层 用户)
com.gy.web.IndexServlet.java
//登录成功会跳转到这个页面 进行处理
package com.gy.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/indexServlet")
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("进入首页....");
// 设置首页导航栏高亮值
request.setAttribute("menu_page", "index");
// 1. 设置首页动态包含的页面值,存到request作用域中
//为了 做成 动态包含
request.setAttribute("changePage", "note/list.jsp");
// 2. 请求转发跳转到首页
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
com.gy.web.UserServlet.java
package com.gy.web;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import com.gy.po.User;
import com.gy.po.vo.ResultInfo;
import com.gy.service.UserService;
/**
* 用户模块
* 用户行为 actionName
用户登录 actionName=login
用户退出 actionName=logout
进入个人中心 actionName=userCenter
加载头像 actionName=userHead
验证昵称的唯一性 actionName=checkNick
修改用户信息(上传文件) actionName=updateInfo
*/
@MultipartConfig // 如果前台是文件上传表单,则必须加这个注解
@WebServlet("/userServlet")
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private UserService userService = new UserService();
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("用户模块...");
// 设置首页导航栏高亮值
request.setAttribute("menu_page", "user");
//用户行为
// 得到用户行为
String actionName = request.getParameter("actionName");
// 判断用户行为
if ("login".equals(actionName)) {
// 用户登录
userLogin(request, response);
} else if ("logout".equals(actionName)) {
// 用户退出
userLogout(request, response);
} else if ("userCenter".equals(actionName)) {
// 进入个人中心
userCenter(request, response);
} else if ("userHead".equals(actionName)) {
// 加载头像
userHead(request, response);
} else if ("checkNick".equals(actionName)) {
// 验证昵称的唯一性
checkNick(request, response);
} else if ("updateInfo".equals(actionName)) {
// 修改用户信息
updateInfo(request,response);
} else {
// 当actionName为空时,跳转到登录页面
response.sendRedirect("login.jsp");
}
}
/**
* 修改用户信息
1、调用Service层的方法,返回resultInfo对象
2、将resultInfo对象存到request作用域中
3、请求转发跳转到个人中心 userServlet?actionName=userCneter
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
//修改用户信息servlet
private void updateInfo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、调用Service层的方法,返回resultInfo对象
ResultInfo<User> resultInfo = userService.updateInfo(request);
// 2、将resultInfo对象存到request作用域中
request.setAttribute("resultInfo", resultInfo);
// 3、请求转发跳转到个人中心 userServlet?actionName=userCneter
request.getRequestDispatcher("userServlet?actionName=userCenter").forward(request, response);
}
/**
* 验证昵称的唯一性
1、接收参数
2、从session域对象中得到用户对象,从而得到用户ID
3、调用Service层的防范,返回结果 (0或1)
4、通过输出流响应结果(需要将数值转成字符串)
* @param request
* @param response
* @throws IOException
*/
//昵称唯一servlet
private void checkNick(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1、接收参数
String nickName = request.getParameter("nickName");
// 2、从session域对象中得到用户对象,从而得到用户ID
User user = (User) request.getSession().getAttribute("user");
Integer userId = user.getUserId();
// 3、调用Service层的防范,返回结果 (0或1)
int code = userService.checkNick(nickName, userId);
// 4、通过输出流响应结果(需要将数值转成字符串)
response.getWriter().write(""+code);
response.getWriter().close();
}
/**
* 用户退出
1、销毁session
2、删除cookie
3、跳转到登录页面
* @param request
* @param response
* @throws IOException
*/
//用户退出servlet
private void userLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1、销毁session
request.getSession().invalidate();
// 2、删除cookie //因为要删除 第二个参数任意
Cookie cookie = new Cookie("user",null);
cookie.setMaxAge(0);
response.addCookie(cookie);
// 3、跳转到登录页面
response.sendRedirect("login.jsp");
}
/**
* 加载用户头像
1、得到参数(图片名)
2、得到图片的存放路径
3、通过路径,得到file对象
4、判断file对象是否存在,并且是一个标准文件
5、得到图片的后缀
6、根据不同的后缀设置对应的响应类型
7、将文件对象通过工具类FileUtils.copyFile()响应给客户端
* @param request
* @param response
* @throws IOException
*/
//加载头像servlet
private void userHead(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1、得到参数(图片名)
String imageName = request.getParameter("imageName");
// 2、得到图片的存放路径
String path = request.getServletContext().getRealPath("/WEB-INF/upload/");
// 3、通过路径,得到file对象
File file = new File(path + imageName);
// 4、判断file对象是否存在,并且是一个标准文件
if (file.exists() && file.isFile()) {
// 5、得到图片的后缀
String pic = imageName.substring(imageName.lastIndexOf(".")+1);
// 6、根据不同的后缀设置对应的响应类型
if ("PNG".equalsIgnoreCase(pic)) {
response.setContentType("image/png");
} else if ("GIF".equalsIgnoreCase(pic)) {
response.setContentType("image/gif");
} else if ("JPG".equalsIgnoreCase(pic) || "JPEG".equalsIgnoreCase(pic)) {
response.setContentType("image/jpeg");
}
// 7、将文件对象通过工具类FileUtils.copyFile()响应给客户端
//需要提前 导包
FileUtils.copyFile(file, response.getOutputStream());
}
}
/**
* 进入个人中心
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
//个人中心 servlet
private void userCenter(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置首页动态包含的页面值
request.setAttribute("changePage", "user/info.jsp");
// 请求转发跳转到首页
request.getRequestDispatcher("index.jsp").forward(request, response);
}
/**
* 用户登录
1、接收参数
2、调用Service层的方法,得到resultInfo对象
3、判断resultInfo的code的值,判断是否登录成功
如果失败,将resultInfo对象存到request作用域中,请求转发跳转到登录页面
如果成功
1、将用户对象存到session作用域中
2、判断用户是否选择记住密码
如记住,,则存cookie对象
3、重定向跳转到indexServlet
*/
//用户登录 servlet
private void userLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、接收参数
String uname = request.getParameter("userName");
String upwd = request.getParameter("userPwd");
// 2、调用Service层的方法,得到resultInfo对象
ResultInfo<User> resultInfo = userService.userLogin(uname, upwd);
// 3、判断resultInfo的code的值,判断是否登录成功
if (resultInfo.getCode() == 1) {
// 1、将用户对象(结果集)存到session作用域中 键值
request.getSession().setAttribute("user", resultInfo.getResult());
// 2、判断用户是否选择记住密码 如记住,,则存cookie对象
String rem = request.getParameter("rem");
if ("1".equals(rem)) {
// 存cookie对象
Cookie cookie = new Cookie("user",uname+ "-" + upwd);
// 设置失效时间
cookie.setMaxAge(3*24*60*60);
// 响应cookie
response.addCookie(cookie);
}
// 3、重定向跳转到indexServlet
response.sendRedirect("indexServlet");
} else {
// 如果失败,将resultInfo对象存到request作用域中,请求转发跳转到登录页面
request.setAttribute("resultInfo", resultInfo);
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
com.gy.service(业务逻辑层 用户)
com.gy.service.UserService.java
package com.gy.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import com.gy.dao.UserDao;
import com.gy.po.User;
import com.gy.po.vo.ResultInfo;
import com.gy.util.MD5Util;
import com.gy.util.StringUtil;
public class UserService {
private UserDao userDao = new UserDao();
/**
* 用户登录
1、判断参数是否为空
如果为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
2、调用Dao层的查询方法,通过用户名查询用户对象,返回用户对象
如果用户对象为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
3、如果存在,将数据库中的密码与前台传递的密码作比较
如果不正确,设置resultInfo对象的code和msg的值,
如果正确,设置resultInfo的code=1,
4、返回resultInfo给servlet层
* @param uname
* @param upwd
* @return
*/
//用户登录 service
public ResultInfo<User> userLogin(String uname, String upwd) {
ResultInfo<User> resultInfo = new ResultInfo<>();
// 数据回显
User u = new User();
u.setUname(uname);
u.setUpwd(upwd);
resultInfo.setResult(u);
// 1、判断参数是否为空
if (StringUtil.isEmpty(uname) || StringUtil.isEmpty(upwd)) {
// 如果为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
resultInfo.setCode(0);
resultInfo.setMsg("用户名或密码不能为空!!");
return resultInfo;
}
// 2、调用Dao层的查询方法,通过用户名查询用户对象,返回用户对象
User user = userDao.findUserByUname(uname);
// 判断用户对象是否为空
if (user == null) {
// 如果用户对象为空,设置resultInfo对象的code和msg的值,返回resultInfo给servlet层
resultInfo.setCode(0);
resultInfo.setMsg("用户不存在!");
return resultInfo;
}
// 因为数据库中的密码是加密过的,所以我们先将前台传递过来的密码加密后再与数据库比较
upwd = MD5Util.encode(MD5Util.encode(upwd));
// 3、如果存在,将数据库中的密码与前台传递的密码作比较
if (upwd.equals(user.getUpwd())) {
// 如果正确,设置resultInfo的code=1
resultInfo.setCode(1);
resultInfo.setResult(user); // 用来存session作用域的
} else {
// 如果不正确,设置resultInfo对象的code和msg的值
resultInfo.setCode(0);
resultInfo.setMsg("用户密码不正确!!");
}
return resultInfo;
}
/**
* 验证昵称的唯一性
1、判断参数是否为空
如果为空,返回0
2、调用Dao层,通过昵称和用户ID查询数据库中除了当前记录之后是否有其他记录使用该昵称,返回user对象
3、判断user对象是否为空
如果为空,返回1
如果不为空,返回0
* @param nickName
* @param userId
* @return
*/
//昵称唯一service
public int checkNick(String nickName, Integer userId) {
// 1、判断参数是否为空
if (StringUtil.isEmpty(nickName)) {
return 0;
}
// 2、调用Dao层,通过昵称和用户ID查询数据库中除了当前记录之后是否有其他记录使用该昵称,返回user对象
User user = userDao.findUserByNickAndUserId(nickName, userId);
// 3、判断user对象是否为空
if (user != null) {
return 0;
}
return 1;
}
/**
* 修改用户信息
1、接收参数 (昵称、心情)
2、参数非非空判断 (昵称)
3、从session作用域中得到user对象,得到用户ID
4、===实现文件上传====
1、得到Part对象 request.getPart("name") "name"代表的是前台的file文件域的name属性值
2、得到上传的文件名
3、判断文件名是否不为空
如果为空,表示未上传文件
如果不为空,则得到文件要存放的地址
4、上传文件到指定路径
5、如果上传了文件,则修改用户头像,否则使用原来的头像
6、调用Dao层的修改方法,返回受影响的行数
7、判断受影响的行数
如果大于0,成功,更新session作用域中色user对象
如果不大于0,失败
* @param request
* @return
*/
//修改用户信息service
public ResultInfo<User> updateInfo(HttpServletRequest request) {
ResultInfo<User> resultInfo = new ResultInfo<>();
// 1、接收参数 (昵称、心情)
String nickName = request.getParameter("nick11");
String mood = request.getParameter("mood");
// 2、参数非非空判断 (昵称)
if (StringUtil.isEmpty(nickName)) {
resultInfo.setCode(0);
resultInfo.setMsg("用户昵称不能为空!");
return resultInfo;
}
// 3、从session作用域中得到user对象,得到用户ID
User user = (User) request.getSession().getAttribute("user");
// 验证昵称的唯一性
int code = checkNick(nickName, user.getUserId());
// 判断昵称是否可用
if (code != 1) {
resultInfo.setCode(0);
resultInfo.setMsg("用户昵称已存在,请重试!");
return resultInfo;
}
String head = user.getHead(); // 原本的头像值
// ===实现文件上传====
try {
// 1、得到Part对象 request.getPart("name") "name"代表的是前台的file文件域的name属性值
Part part = request.getPart("img");
// 2、得到上传的文件名
String fileName = part.getSubmittedFileName();
// 3、判断文件名是否不为空
if (!StringUtil.isEmpty(fileName)) {
// 重新给头像赋值
head = fileName;
// 如果不为空,则得到文件要存放的地址
String path = request.getServletContext().getRealPath("/WEB-INF/upload/");
// 4、上传文件到指定路径
part.write(path + fileName);
}
//如果为空,表示未上传文件
} catch (Exception e) {
e.printStackTrace();
}
// 重新给user对象赋值
user.setNick(nickName);
user.setMood(mood);
user.setHead(head);
// 6、调用Dao层的修改方法,返回受影响的行数
int row = userDao.updateUser(user);
// 7、判断受影响的行数
if (row >0) {
// 如果大于0,成功,更新session作用域中色user对象
request.getSession().setAttribute("user", user);
resultInfo.setCode(1);
resultInfo.setMsg("修改成功!");
} else {
resultInfo.setCode(0);
resultInfo.setMsg("修改失败!");
}
return resultInfo;
}
}
com.gy.Dao
com.gy.Dao.UserDao.java
package com.gy.dao;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gy.po.User;
public class UserDao {
// 使用日志工厂类
private static Logger logger = LoggerFactory.getLogger(UserDao.class);
/**
* 通过用户名查询用户对象是否存在
1、得到数据库连接
2、定义sql语句
3、预编译
4、设置参数,下标从1开始
5、执行查询,返回结果集
6、判断并分析结果集,得到用户对象
7、关闭资源
8、返回用户对象
* @return
*/
//原生用户登录Dao
/*
public User findUserByUname(String uname) {
User user = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1、得到数据库连接
connection = DBUtil.getConnection();
// 2、定义sql语句
String sql = "select * from tb_user where uname = ? ";
logger.info("当前sql语句:" + sql);
logger.info("当前sql语句2:{}",sql);
// 3、预编译
preparedStatement = connection.prepareStatement(sql);
// 4、设置参数,下标从1开始
preparedStatement.setString(1, uname);
// 5、执行查询,返回结果集
resultSet = preparedStatement.executeQuery();
// 6、判断并分析结果集,得到用户对象
if (resultSet.next()) {
user = new User();
user.setHead(resultSet.getString("head"));
user.setMood(resultSet.getString("mood"));
user.setNick(resultSet.getString("nick"));
user.setUname(uname);
user.setUpwd(resultSet.getString("upwd"));
user.setUserId(resultSet.getInt("userId"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
DBUtil.close(connection, preparedStatement, resultSet);
}
return user;*/
//用户登录Dao
public User findUserByUname(String uname) {
// 1、定义sql语句
String sql = "select * from tb_user where uname = ? ";
// 2、参数集合
List<Object> params = new ArrayList<>();
params.add(uname);
// 3、调用BaseDao
User user = (User) BaseDao.queryRow(sql, params, User.class);
return user;
}
/**
* 通过昵称和用户ID查询数据库中除了当前记录之后是否有其他记录使用该昵称,返回user对象
* @param nickName
* @param userId
* @return
*/
原生判断昵称唯一Dao
/*public User findUserByNickAndUserId(String nickName, Integer userId) {
User user = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1、得到数据库连接
connection = DBUtil.getConnection();
// 2、定义sql语句
String sql = "select * from tb_user where nick = ? and userId != ?";
// 3、预编译
preparedStatement = connection.prepareStatement(sql);
// 4、设置参数,下标从1开始
preparedStatement.setString(1, nickName);
preparedStatement.setInt(2, userId);
// 5、执行查询,返回结果集
resultSet = preparedStatement.executeQuery();
// 6、判断并分析结果集,得到用户对象
if (resultSet.next()) {
user = new User();
user.setHead(resultSet.getString("head"));
user.setMood(resultSet.getString("mood"));
user.setNick(resultSet.getString("nick"));
user.setUname(resultSet.getString("uname"));
user.setUpwd(resultSet.getString("upwd"));
user.setUserId(resultSet.getInt("userId"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
DBUtil.close(connection, preparedStatement, resultSet);
}
return user;*/
//昵称唯一Dao
public User findUserByNickAndUserId(String nickName, Integer userId)
String sql = "select * from tb_user where nick = ? and userId != ?";
List<Object> params = new ArrayList<>();
params.add(nickName);
params.add(userId);
User user = (User) BaseDao.queryRow(sql, params, User.class);
return user;
}
/**
* 通过用户OD修改用户对象
* 定义sql语句
* 定义参数集合
* 调用BaseDao的更新方法
* @param user
* @return
*/
//修改用户信息Dao
public int updateUser(User user) {
// 定义sql语句
String sql = "update tb_user set nick = ?, mood = ?, head = ? where userId = ?";
// 定义参数集合
List<Object> params = new ArrayList<Object>();
params.add(user.getNick());
params.add(user.getMood());
params.add(user.getHead());
params.add(user.getUserId());
// 调用BaseDao的更新方法
int row = BaseDao.executeUpdate(sql, params);
return row;
}
}
com.gy.filter
//乱码过滤器
com.gy.filter.EncodeFilter.java
package com.gy.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
/**
* 请求乱码问题
*
* Tomcat8及以上版本 Tomcat7及以下版本
* POST请求 会乱码,request.setCharacterEncoding("UTF-8"); 会乱码,request.setCharacterEncoding("UTF-8");
*
* GET请求 不会乱码,不处理 会乱码,new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
*/
@WebFilter("/*")
public class EncodeFilter implements Filter {
public EncodeFilter() {}
public void destroy() {}
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
// 基于HTTP
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 处理POST请求乱码 (无论什么版本服务器)
request.setCharacterEncoding("UTF-8");
// 处理GET请求乱码
// 1、得到请求类型
String method = request.getMethod();
// 2、判断是否是GET请求
if ("GET".equalsIgnoreCase(method)) {
// 3、如果是GET请求,则获取服务器版本信息
String serverInfo = request.getServletContext().getServerInfo();
//System.out.println(serverInfo);
// 4、得到服务器的版本号
String versionStr = serverInfo.substring(serverInfo.lastIndexOf("/")+1,serverInfo.lastIndexOf("/")+2);
// 5、判断是否是Tomcat8以下版本服务器
if (Integer.parseInt(versionStr) < 8) {
// new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
// 定义类,继承HttpServletRequestWrapper封装类,重写getParameter()方法,返回的类的本质是request对象
HttpServletRequest req = new MyWapper(request);
// 放行指定request对象 (Ttomcat7及以下版本的GET请求)
chain.doFilter(req, response);
return;
}
}
// POST请求和Ttomcat8及以上版本的GET请求放行
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
/**
* 1、定义类
* 2、继承HttpServletRequestWrapper封装类
* 3、重写getParameter()方法
*
*/
class MyWapper extends HttpServletRequestWrapper {
// 定义属性。提升作用域
private HttpServletRequest request;
/**
* 带参构造器
* @param request
*/
public MyWapper(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 重写getParameter()方法,处理乱码问题
*/
@Override
public String getParameter(String name) { // name代表的是前台传递的参数名,即键
// 获取参数的值
String value = request.getParameter(name);
// 判断值是否为空,不为空处理乱码问题
if (value == null || "".equals(value.trim())) {
return value;
}
try {
// 处理乱码问题
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
}
com.gy.LoginAccessFilter.java
//自动登录过滤器
package com.gy.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.gy.po.User;
//先全部拦截
@WebFilter("/*") //不可少的标识
public class LoginAccessFilter implements Filter {
public LoginAccessFilter() {}//构造器???
public void destroy() {}
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain)
throws IOException, ServletException {
// 基于HTTP
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 得到请求的路径
String path = request.getRequestURI();
// 1、指定页面,放行 (无需登录即可访问的页面需要放行,如登录、注册等页面)
if (path.contains("/login.jsp")) {
chain.doFilter(request, response);
return;
}
// 2、静态资源,放行 (js、css、images等静态资源需要放行,项目中statics目录下的资源都放行)
if (path.contains("/statics")) {
chain.doFilter(request, response);
return;
}
// 3、指定行为,放行 (无需登录即可执行的操作需要放行,如登录操作、注册操作等)
// 判断是否是用户模块
if (path.contains("/userServlet")) { // "userServlet"代表的是对应的Servlet的对外访问路径
// 在 UserServlet中查询 在其页面的操作&&已登陆
// 得到用户行为
String actionName = request.getParameter("actionName");
if ("login".equals(actionName)) {
chain.doFilter(request, response);
return;
}
}
// 4、登录状态,放行 (判断session中的user对象是否为空;不为空则为登录状态)
// 得到session域对象中的user对象
User user = (User) request.getSession().getAttribute("user");
// 判断user对象是否为空
if (user != null) {
chain.doFilter(request, response);
return;
}
// EX 如果用户是非登录状态 //这部视为拦截
// 判断cookie是否存在
Cookie[] cookies = request.getCookies();
// 判断cookie数组是否为空
if (cookies != null && cookies.length > 0) {
// 遍历cookie数组
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
// 得到指定名称的cookie的值
if ("user".equals(name)) {
//格式示例: admin-123456
// 得到用户名称和密码
//剪裁之后是个数组
String uname = value.split("-")[0];
String upwd = value.split("-")[1];
// 拼接 登录的地址
String url = "userServlet?actionName=login&userName="+uname+"&userPwd="+upwd;
// 请求转发跳转登录操作
request.getRequestDispatcher(url).forward(request, response);
return;
}
}
}
// 拦截跳转到登录页面
response.sendRedirect("login.jsp");
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
com.gy.util
com.gy.util.DBUtil.java
//JDBC工具类
package com.gy.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
/**
* 数据库工具类
* 1、打开数据库连接
* 2、关闭资源
*
* 常见的报错情况:
* 1、数据库的jar包未拷贝到lib目录下
* java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
* 2、数据库的密码可能不正确:
* java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
* 3、数据库名称不正确
* com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'java29'
*
*/
public class DBUtil {
// 得到配置文件对象
private static Properties properties = new Properties();
static {
try {
// 得到db.properties的输入流对象
InputStream inputStream = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
// 通过properties的load()方法,加载配置文件的输入流
properties.load(inputStream);
} catch (Exception e) {
// 打印异常
e.printStackTrace();
}
}
/**
* 得到数据库连接
* 1、加载驱动
* 2、通过地址、账号、密码得到数据库连接
* @return
*/
public static Connection getConnection() {
Connection connection = null;
// 从配置对象中获取参数 getProperty()
String jdbcName = properties.getProperty("jdbcName");
String dbUrl = properties.getProperty("dbUrl");
String dbName = properties.getProperty("dbName");
String dbPwd = properties.getProperty("dbPwd");
try {
// 1、加载驱动
Class.forName(jdbcName);
// 2、通过地址、账号、密码得到数据库连接
connection = DriverManager.getConnection(dbUrl, dbName, dbPwd);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
/**
* 关闭资源
* @param connection
* @param preparedStatement
* @param resultSet
*/
public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
// 关闭资源
try {
// 先判断不为空,再关闭
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(getConnection());
}
}
com.gy.util.JsonUtil.java
//Json对象工具类
package com.gy.util;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
/**
* 将对象转换成JSON字符串,并响应给ajax的回调函数
*
*/
public class JsonUtil {
public static void toJson(HttpServletResponse response, Object object) throws IOException {
// 1、设置响应类型及编码
response.setContentType("application/json;charset=UTF-8");
// 2、得到输出流
PrintWriter out = response.getWriter();
// 将对象转换成json格式的字符串
String json = JSON.toJSONString(object);
// 将json字符串响应给ajax的回调函数
out.write(json);
// 关闭资源
out.close();
}
}
com.gy.util.MD5Util.java
//MD5工具类
package com.gy.util;
import java.security.MessageDigest;
import org.apache.tomcat.util.codec.binary.Base64;
/**
* 将字符串通过md5加密,返回加密后的字符串
*
*/
public class MD5Util {
public static String encode(String str) {
String value = "";
try {
// 得到md5的加密程序
MessageDigest messageDigest = MessageDigest.getInstance("md5");
// 加密字符串,得到byte数组
byte[] bytes = messageDigest.digest(str.getBytes());
// 通过Base64编码,将byte数组转换成字符串
value = Base64.encodeBase64String(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
public static void main(String[] args) {
System.out.println(MD5Util.encode(MD5Util.encode("123456")));
}
}
com.gy.util.StringUtil.java
//String工具类
package com.gy.util;
/**
* 字符串工具类
*
*/
public class StringUtil {
/**
* 判断字符串是否为空
* 为空,返回true;否则返回false
* @param str
* @return
*/
public static boolean isEmpty(String str) {
if (str == null || "".equals(str.trim())) {
return true;
}
return false;
}
}
properties
log4j.properties
### 设置###stdout,
### 解开下面注释 log4j.rootLogger=all,D,E,stdout
### 输出信息到控制台 ###
### 解开下面注释
###log4j.appender.stdout=org.apache.log4j.ConsoleAppender
###log4j.appender.stdout.Target=System.out
###log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
###log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出 DEBUG 级别以上的日志到=D://logs/error.log ###
### 解开下面注释
###log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
###log4j.appender.D.File=D://logs/log.log
###log4j.appender.D.Append=true
###log4j.appender.D.Threshold=DEBUG
###log4j.appender.D.layout=org.apache.log4j.PatternLayout
###log4j.appender.D.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] -[ %p ] %m%n
### 输出 ERROR 级别以上的日志到=E://logs/error.log ###
### 解开下面注释
###log4j.appender.E=org.apache.log4j.DailyRollingFileAppender
###log4j.appender.E.File=E://logs/error.log
###log4j.appender.E.Append=true
###log4j.appender.E.Threshold=ERROR
###log4j.appender.E.layout=org.apache.log4j.PatternLayout
###log4j.appender.E.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ]