数据库配置文件
创建 db.properties 资源文件,存放配置信息
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javaweb?useSSL=true&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
操作数据库公共类
建立 dao 包,然后创建 BaseDao 类
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class BaseDao {
private static String driver;
private static String url;
private static String username;
private static String password;
//静态代码块,类加载的时候初始化
static {
Properties properties = new Properties();
//通过类加载器读取对应的资源
InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
//获取数据库的连接
public static Connection getConnection(){
Connection connection = null;
try {
Class.forName(driver);
connection = DriverManager.getConnection(url,username,password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
//编写预编译查询公共方法
public static ResultSet execute(Connection con, PreparedStatement pre, ResultSet rs, String sql, Object[] params) throws SQLException {
rs=null;
if(con!=null){
pre = con.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pre.setObject(i+1,params[i]);
}
rs = pre.executeQuery();
}
return rs;
}
//编写预编译增删改公共方法
public static int execute(Connection con, PreparedStatement pre, String sql, Object[] params) throws SQLException {
int updateRows = 0;
if(con!=null){
pre = con.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pre.setObject(i+1,params[i]);
}
updateRows = pre.executeUpdate();
}
return updateRows;
}
//释放资源
public static boolean closeResource(Connection con, PreparedStatement pre, ResultSet rs){
boolean flag = true;
if(con!=null){
try{
con.close();
con = null; //GC回收
}catch (SQLException e){
e.printStackTrace();
flag = false;
}
}
if(pre!=null){
try {
pre.close();
pre = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
if(rs!=null){
try {
rs.close();
rs = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
return flag;
}
}
字符编码过滤器
建立 filter 包,然后在包下建立CharacterEncodingFilter 类
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
chain.doFilter(request,response);
}
@Override
public void destroy() {}
}
在 web.xml 下注册编码过滤器,路径根据自己需要更改
<!-- 字符编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.qiu.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
建立实体对象
建立 pojo 包,然后根据数据库建立对应的实体类
以user表为例,建立 User 类,根据数据库字段建立对应私有属性,然后建立 get/set 方法,创建有参/无参构造方法
数据库操作实体类
建立 user 包,然后建立 UserDao 接口,面向接口编程
public interface UserDao {
//得到要登录的用户信息
public User getLoginUser(Connection con, String username, String password) throws SQLException;
//修改当前用户密码
public int updatePwd(Connection con, String username, String password)throws SQLException;
}
编写接口实现类 UserDaoImpl
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDaoImpl implements UserDao {
//得到要登录的用户
public User getLoginUser(Connection con, String username, String password) throws SQLException {
PreparedStatement pre = null;
ResultSet rs = null;
User user = null;
if(con!=null){
String sql = "select * from user where username=? and password=?";
Object[] params = {username,password};
rs = BaseDao.execute(con, pre, rs, sql, params);
if(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
BaseDao.closeResource(null,pre,rs);
}
return user;
}
//修改当前用户密码
public int updatePwd(Connection con, String username, String password) throws SQLException {
PreparedStatement pre = null;
int updateRows = 0;
if(con!=null){
String sql = "update user set password = ? where username = ?";
Object[] params = {password,username};
updateRows = BaseDao.execute(con, pre, sql, params);
BaseDao.closeResource(null, pre, null);
}
return updateRows;
}
}
业务层接口及实现类
建立 service 包,并在 service 包下建立 user 包
然后编写 UserService 接口
public interface UserService {
//得到登录信息
public User login(String username, String password);
//根据用户ID 修改密码
public boolean updatePwd(String username, String password);
}
编写接口实现类UserServiceImpl
public class UserServiceImpl implements UserService {
//业务层都会调用dao层,所以我们要引入dao层
private UserDao userDao;
public UserServiceImpl(){
userDao = new UserDaoImpl();
}
@Override
public User login(String username, String password) {
Connection con = null;
User user = null;
con = BaseDao.getConnection();
//通过业务层调用对应的具体的数据库操作
try {
user = userDao.getLoginUser(con,username,password);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(con,null,null);
}
return user;
}
@Override
public boolean updatePwd(String username, String password){
Connection con = null;
boolean flag = false;
//根据用户ID 修改密码
try{
con = BaseDao.getConnection();
if(userDao.updatePwd(con, username, password)>0){
flag=true;
}
}catch (SQLException e){
e.printStackTrace();
try {
con.rollback();//数据库回滚操作
} catch (SQLException ex) { ex.printStackTrace(); }
}finally {
BaseDao.closeResource(con,null,null);
}
return flag;
}
}
控制层实现类
建立 servlet 包,然后建立 user 包
在user包下建立 LoginServlet 类来处理登录请求
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 LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
//和数据库中的账号密码进行对比,调用业务层
UserService userService = new UserServiceImpl();
User user = userService.login(username, password);
if(user!=null){
//将用户信息放到Session中
req.getSession().setAttribute(Constants.USER_SESSION,user);
//跳转到主页
resp.sendRedirect(req.getContextPath()+"/main/success.jsp");
}else{
//转发回登录页面,顺带提示它,用户名或者密码错误
req.setAttribute(Constants.MESSAGE,"用户名或者密码错误");
req.getRequestDispatcher("/login/login.jsp").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册 LoginServlet
<!--login-->
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.qiu.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
在user包下建立 UserServlet 类来处理修改密码请求
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 UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从Session里面拿到username
Object obj = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
boolean flag = true;
if(obj!=null && !StringUtils.isNullOrEmpty(newpassword)){
UserService userService = new UserServiceImpl();
flag = userService.updatePwd(((User)obj).getUsername(),newpassword);
if(flag){
req.setAttribute(Constants.MESSAGE,"密码修改成功,请退出重新登录");
req.getSession().removeAttribute(Constants.USER_SESSION);
}else{
req.setAttribute(Constants.MESSAGE,"密码修改失败");
}
}else{
req.setAttribute(Constants.MESSAGE,"新密码存在问题");
}
req.getRequestDispatcher("/main/updatePwd.jsp").forward(req,resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册 UserServlet
<!--user-->
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.qiu.servlet.user.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/main/user.do</url-pattern>
</servlet-mapping>
<servlet>
编写常用工具类
建立 util 包,然后建立常用变量工具类 Constants
以后的常量放在工具类下
public class Constants {
public final static String USER_SESSION = "userSession";
public final static String MESSAGE = "message";
}
编写注销功能
思想:移除Session,然后重定向到登录页面
在servlet包中的user包内建立LogoutServlet类
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//移除用户的Constants.USER_SESSION
req.getSession().removeAttribute(Constants.USER_SESSION);
resp.sendRedirect(req.getContextPath()+"/login/login.jsp");//返回登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册Servlet
<!--logout-->
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>com.qiu.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/logout.do</url-pattern>
</servlet-mapping>
在jsp下面应用logout.do,以a标签为例
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<a href="<c:url value="/logout.do"/>">退出</a>
登录拦截优化
思想:请求页面时,判断是否存在Session
在 filter 包下建立登录过滤器 SysFilter
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//过滤器,从Session中获取用户
User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);
if(user==null){ //已被移除或者注销了,或者未登录
response.sendRedirect(request.getContextPath()+"/login/login.jsp");
}else {
chain.doFilter(req, resp);
}
}
@Override
public void destroy() {}
}
注册过滤器
<!-- 用户登录过滤器-->
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.qiu.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/main/*</url-pattern>
</filter-mapping>
UserServlet优化细节
- 验证密码使用ajax及时动态优化
- 实现Servlet复用
- 使用前引入fastjson依赖
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
//实现Servlet复用
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if(method!=null && method.equals("savepwd")){
this.updataPwd(req,resp);
}else if(method!=null && method.equals("pwdmodify")){
this.pwdModify(req,resp);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
//修改密码
public void updataPwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从Session里面拿到username
Object obj = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
boolean flag;
if(obj!=null && !StringUtils.isNullOrEmpty(newpassword)){
UserService userService = new UserServiceImpl();
flag = userService.updatePwd(((User)obj).getUsername(),newpassword);
if(flag){
req.setAttribute(Constants.MESSAGE,"密码修改成功,请退出重新登录");
req.getSession().removeAttribute(Constants.USER_SESSION);
}else{
req.setAttribute(Constants.MESSAGE,"密码修改失败");
}
}else{
req.setAttribute(Constants.MESSAGE,"新密码存在问题");
}
req.getRequestDispatcher("/main/updatePwd.jsp").forward(req,resp);
}
//验证旧密码,session中有用户的密码
public void pwdModify(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Object obj = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = req.getParameter("oldpassword");
//万能的Map:结果集
Map<String,String> resultMap = new HashMap<String,String>();
if(obj==null){//session失效过期了
resultMap.put("result","sessionError");
}else if(StringUtils.isNullOrEmpty(oldpassword)){ //输入的密码为空
resultMap.put("result","error");
}else{
String userPassword = ((User)obj).getPassword();
if(oldpassword.equals(userPassword)){
resultMap.put("result","true");
}else{
resultMap.put("result","false");
}
}
resp.setContentType("application/json");
PrintWriter writer = resp.getWriter();
//JSONArray 阿里巴巴的JSON工具类,转换格式
writer.write(JSONArray.toJSONString(resultMap));
writer.flush();
writer.checkError();
}
}
updatePwd.jsp 文件,根据环境做不同的修改
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta charset="utf-8">
<title>修改密码</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login/css/style.css"/>
<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_1808293_ftumhpfd07g.css"/>
<script src="${pageContext.request.contextPath}/login/js/jQuery.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div class="form-wrapper">
<div class="header">
修改密码
</div>
<form action="${pageContext.request.contextPath}/main/user.do" method="post" class="update-form">
<input type="hidden" name="method" value="savepwd">
<div class="input-wrapper">
<div class="border-wrapper">
<input id="oldpassword" type="password" name="password" placeholder="旧密码" class="border-item" value="" required/>
</div>
<div class="border-wrapper">
<input id="newpassword" type="password" name="newpassword" placeholder="新密码" class="border-item" value="" required/>
</div>
<div class="border-wrapper">
<input id="rnewpassword" type="password" name="rnewpassword" placeholder="确认密码" class="border-item" value="" required/>
</div>
</div>
<div class="action">
<div id="save" class="btn" onclick="send()">提交</div>
</div>
</form>
<div id="message" style="color:red;font-size: 1.2em;margin-top: 20px">${message}</div>
</div>
<script>
let oldpassword = null;
let newpassword = null;
let rnewpassword = null;
let saveBtn = null;
let message = null;
let path = "${pageContext.request.contextPath}";
$(function () {
oldpassword = $("#oldpassword");
newpassword = $("#newpassword");
rnewpassword = $("#rnewpassword");
saveBtn = $("#save");
message = $("#message");
oldpassword.on("focus",function (){
message.html("请输入原来密码!");
}).on("blur",function () {
$.ajax({
type:"GET",
url:path+"/main/user.do",
data:{method:"pwdmodify",oldpassword:oldpassword.val()},
//上面等价于 path+"/main/user.do?method=pwdmodify&oldpassword=oldpassword.val()"
dataType:"json",
success:function (data) {
if(data.result === "true"){ //旧密码正确
message.html("旧密码验证成功!");
}else if(data.result ==="false"){
message.html("原密码输入不正确!");
}else if(data.result ==="sessionError"){
message.html("当前用户session过期,请重新登陆!");
}else if(data.result ==="error"){
message.html("请输入旧密码!");
}
},
error:function (data) {
//请求出错
message.html("请求出错!");
}
});
});
//新密码
newpassword.on("focus",function () {
message.html("密码长度必须是大于6位小于20位!");
}).on("blur",function () {
if(newpassword.val()!=null && newpassword.val().length>=6
&& newpassword.val().length<20){
message.html("新密码符合要求!");
}else{
message.html("密码输入不符合规范,请重新输入");
}
});
//确认密码
rnewpassword.on("focus",function () {
message.html("请输入与上面一致的密码");
}).on("blur",function () {
if(newpassword.val()!=null && newpassword.val().length>=6
&& newpassword.val().length<20 && newpassword.val() === rnewpassword.val()){
message.html("确认密码符合要求!");
}else{
message.html("两次密码输入不一致,请重新输入!");
}
});
});
function send(){
if(message.html()==="密码修改成功,请退出重新登录" || (oldpassword.val().length!==0 && newpassword.val().length!==0 && rnewpassword.val().length!==0)){
document.getElementsByClassName("update-form")[0].submit();
}else{
message.html("存在未填项,请重新检查!");
}
}
</script>
</body>
</html>
补充内容
- 设置欢迎页和 Session 过期时间
<!-- 设置欢迎页-->
<welcome-file-list>
<welcome-file>/login/login.jsp</welcome-file>
</welcome-file-list>
<!--设置Session默认过期时间(分钟)-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
- fastjson 依赖
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
- 分包情况:pojo 包、 dao 包、 user包、 service 包、 servlet 包、 filter 包、 util 包