1.项目搭建
1. 创建一个maven web项目
2. 配置tomcat
3. 测试项目是否能够跑起来
4. 导入项目中会遇到的jar包: jsp,servlet,mysql驱动,jstl,standard等等
5. 创建项目结构
6. 编写实体类pojo(entity): ORM:表-类映射
7. 编写基础公共类:
1)在resource文件夹下写properties文件
driver=com.mysql.jdbc.Driver
#在和mysql传递数据的过程中,使用unicode编码格式,并且字符集设置为utf-8
url=jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8
user=root
password=123456
2)读properties文件:在dao层,写一个BaseDao.class(数据库的公共类)
/**
* 操作数据库的基类--静态类
* 读取database.properties
* @author Administrator
*
*/
public class BaseDao {
static{
//静态代码块,在类加载的时候执行
init();
}
private static String driver;
private static String url;
private static String user;
private static String password;
//初始化连接参数,从配置文件里获得
public static void init(){
Properties params = new Properties();
String configFile = "database.properties";
//getClassLoader():通过类加载器,可以从不同来源加载类的二进制数据
//getResourceAsStream(configFile):把一个资源(database.properties)变成流
InputStream is = BaseDao.class.getClassLoader().getResourceAsStream(configFile);
try {
params.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver=params.getProperty("driver");
url=params.getProperty("url");
user=params.getProperty("user");
password=params.getProperty("password");
}
/**
* 获取数据库连接
* @return
*/
public static Connection getConnection(){
Connection connection = null;
try {
//1.加载驱动 (通过反射得到)
Class.forName(driver);
//2.连接数据库 (connection其实就代表数据库)
connection = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;
}
/**
* 查询操作
* @param connection
* @param preparedStatement
* @param rs
* @param sql
* @param params
* @return
*/
public static ResultSet execute(Connection connection,PreparedStatement preparedStatement,ResultSet rs,
String sql,Object[] params) throws Exception{
//3.预编译(提出去好统一关闭)
preparedStatement = connection.prepareStatement(sql);
for(int i = 0; i < params.length; i++){
//setObject 占位符从1开始,但是数组从0开始
preparedStatement.setObject(i+1, params[i]);
}
rs = preparedStatement.executeQuery();
return rs;
}
/**
* 更新操作(增删改)
* @param connection
* @param preparedStatement
* @param sql
* @param params
* @return
* @throws Exception
*/
public static int execute(Connection connection,PreparedStatement preparedStatement,
String sql,Object[] params) throws Exception{
int updateRows = 0;
preparedStatement = connection.prepareStatement(sql);
for(int i = 0; i < params.length; i++){
preparedStatement.setObject(i+1, params[i]);
}
//就执行方法和查询有不同
updateRows = preparedStatement.executeUpdate();
return updateRows;
}
/**
* 释放资源
* @param connection
* @param preparedStatement
* @param rs
* @return
*/
public static boolean closeResource(Connection connection,PreparedStatement preparedStatement,ResultSet rs){
boolean flag = true;
if(rs != null){
try {
rs.close();
rs = null;//GC回收
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
flag = false;//没有释放成功
}
}
if(preparedStatement != null){
try {
preparedStatement.close();
preparedStatement = null;//GC回收
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
flag = false;
}
}
if(connection != null){
try {
connection.close();
connection = null;//GC回收
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
flag = false;
}
}
return flag;
}
}
3)编写字符编码过滤器
8. 导入静态资源
2.登录功能
1)编写前端页面
2)设置首页(web.xml)
<!--设置欢迎页面-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
3)编写dao层用户登录的接口(dao)
public User getLoginUser(Connection connection, String userCode)throws Exception;
4) 编写dao接口的实现类(dao)
@Override
public User getLoginUser(Connection connection, String userCode)
throws Exception {
// TODO Auto-generated method stub
// 利用BaseDao里的方法,查询登录的用户
PreparedStatement preparedStatement = null;
ResultSet rs = null;
User user = null;
if(null != connection){
//?是占位符,用预编译更安全,
String sql = "select * from smbms_user where userCode=?";
//只有一个参数userCode
Object[] params = {userCode};
rs = BaseDao.execute(connection, preparedStatement, rs, sql, params);
if(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setUserCode(rs.getString("userCode"));
user.setUserName(rs.getString("userName"));
user.setUserPassword(rs.getString("userPassword"));
user.setGender(rs.getInt("gender"));
user.setBirthday(rs.getDate("birthday"));
user.setPhone(rs.getString("phone"));
user.setAddress(rs.getString("address"));
user.setUserRole(rs.getInt("userRole"));
user.setCreatedBy(rs.getInt("createdBy"));
user.setCreationDate(rs.getTimestamp("creationDate"));
user.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getTimestamp("modifyDate"));
}
BaseDao.closeResource(null, preparedStatement, rs);
}
return user;
}
5)业务层接口(service)
public User login(String userCode, String userPassword);//拿到用户名和密码判断
6)业务层实现类(service)
public class UserServiceImpl implements UserService{
//业务层都会调用dao层,所以我们要引入dao层
private UserDao userDao;
public UserServiceImpl(){
userDao = new UserDaoImpl();//延迟加载,实例化UserServiceImpl前,先实例化一个UserDaoImpl对象
}
@Override
public User login(String userCode, String userPassword) {
// TODO Auto-generated method stub
Connection connection = null;
User user = null;
try {
connection = BaseDao.getConnection();
//通过业务层调用对应的具体的数据库操作
user = userDao.getLoginUser(connection, userCode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
BaseDao.closeResource(connection, null, null);
}
//匹配密码
if(null != user){
if(!user.getUserPassword().equals(userPassword))
user = null;
}
return user;
}
7)编写servlet(servlet)处理登陆请求
public class LoginServlet extends HttpServlet {
//servlet:控制层,调用业务层
//处理登陆请求
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("login ============ " );
//获取用户名和密码
String userCode = request.getParameter("userCode");
String userPassword = request.getParameter("userPassword");
//调用service方法,进行用户密码匹配
UserService userService = new UserServiceImpl();
User user = userService.login(userCode,userPassword);//user是登录的人,在这里把登录的人查出来
if(null != user){//查有此人,登录成功
//将用户的信息放入session,以便持续登陆
request.getSession().setAttribute(Constants.USER_SESSION, user);
//页面跳转(frame.jsp)
response.sendRedirect("jsp/frame.jsp");
}else{//查无此人
//页面跳转(login.jsp)带出提示信息--转发回登陆页面
request.setAttribute("error", "用户名或密码不正确");//请求转发可以带数据
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
8)注册servlet并映射
<!--login.jsp里规定了-->
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
9)测试访问
3.登录功能优化
思路:移除session,返回登陆页面
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//清除session
request.getSession().removeAttribute(Constants.USER_SESSION);
//跳转页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
用过滤器实现登录拦截优化:
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("SysFilter doFilter()===========");
HttpServletRequest rq = (HttpServletRequest)request;
HttpServletResponse rp = (HttpServletResponse)response;
//从session中获取用户
User userSession = (User)rq.getSession().getAttribute(Constants.USER_SESSION);
if(null == userSession){//已经被移除或者被注销了
rp.sendRedirect("/smbms/error.jsp");
}else{
chain.doFilter(request, response);
}
}
密码修改
1)导入前端素材
2)写项目建议从底层向上写
3)userDao接口
//修改当前用户密码
public int updatePwd(Connection connection, int id, String pwd)throws Exception;
4)userDao实现类
@Override
public int updatePwd(Connection connection, int id, String pwd)
throws Exception {
// TODO Auto-generated method stub
int flag = 0;//7提上来
PreparedStatement preparedStatement = null;//2
if(connection != null){//6.防止上一层没传过来
String sql = "update smbms_user set userPassword= ? where id = ?";//1
Object[] params = {pwd,id};//3.把参数封装成数组丢进去
flag = BaseDao.execute(connection, preparedStatement, sql, params);//4
BaseDao.closeResource(null, preparedStatement, null);//5
}
return flag;
}
5)UserService层
/**
* 根据userId修改密码
* @param id
* @param pwd
* @return
*/
public boolean updatePwd(int id, String pwd);
6)UserService实现类
@Override
public boolean updatePwd(int id, String pwd) {
boolean flag = false;//递交给前端,证明修改成功
Connection connection = null;
try{
connection = BaseDao.getConnection();//从BaseDao获取连接
//修改密码
if(userDao.updatePwd(connection,id,pwd) > 0)//修改成功
flag = true;
}catch (Exception e) {
e.printStackTrace();
}finally{
BaseDao.closeResource(connection, null, null);
}
return flag;
}
7)记得实现复用,需要提取出方法
private void updatePwd(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//从session里面拿用户id
Object o = request.getSession().getAttribute(Constants.USER_SESSION);
//从pwdmodify.jsp的表单中拿到新密码
String newpassword = request.getParameter("newpassword");
boolean flag = false;
//o != null表示找到了
if(o != null && !StringUtils.isNullOrEmpty(newpassword)){
UserService userService = new UserServiceImpl();
flag = userService.updatePwd(((User)o).getId(),newpassword);
if(flag){
request.setAttribute(Constants.SYS_MESSAGE, "修改密码成功,请退出并使用新密码重新登录!");
request.getSession().removeAttribute(Constants.USER_SESSION);//修改成功,session注销,重新登录
}else{
request.setAttribute(Constants.SYS_MESSAGE, "修改密码失败!");
}
}else{
request.setAttribute(Constants.SYS_MESSAGE, "修改密码失败!");
}
request.getRequestDispatcher("pwdmodify.jsp").forward(request, response);
}
优化密码修改使用AJAX
失去焦点的时候和服务器交互
1)阿里巴巴的fastjson
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
2)pwdmodify.js里运用ajax
oldpassword.on("blur",function(){
$.ajax({//jquery语法
type:"GET",
url:path+"/jsp/user.do",//代表请求提交到哪里
data:{method:"pwdmodify",oldpassword:oldpassword.val()},//ajax传递的参数
dataType:"json",//键值,现在主流开发都是使用JSON实现前后端
success:function(data){//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);
}
});
}).on("focus",function(){
validateTip(oldpassword.next(),{"color":"#666666"},"* 请输入原密码",false);
});
3)UserServlet里验证旧密码
//验证旧密码
private void getPwdByUserId(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//从session里取密码,验证旧密码
Object o = request.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = request.getParameter("oldpassword");
//一切东西都可以存在map里,而不用实体类:结果集
Map<String, String> resultMap = new HashMap<String, String>();
if(null == o ){//session过期(失效)
resultMap.put("result", "sessionerror");//出问题了设置个消息告诉前端
}else if(StringUtils.isNullOrEmpty(oldpassword)){//旧密码输入为空
resultMap.put("result", "error");
}else{
String sessionPwd = ((User)o).getUserPassword();//session中用户的密码
if(oldpassword.equals(sessionPwd)){//前端密码和老密码对比
resultMap.put("result", "true");
}else{//旧密码输入不正确
resultMap.put("result", "false");
}//对应pwdmodify.jsp的四个状态
}
//以上用json接收:用流
response.setContentType("application/json");//类似于"text/html"
PrintWriter outPrintWriter = response.getWriter();
//JSONArray 阿里巴巴的工具类,转换格式
/*
resultMap = ["result", "sessionerror"]
JSON格式 = {key:value}
*/
outPrintWriter.write(JSONArray.toJSONString(resultMap));//转换成json字符串
outPrintWriter.flush();
outPrintWriter.close();
}
用户管理实现
1)导入分页的工具类:pagesupport文件
2)用户列表页面导入:userlist.jsp
1.1 获取用户数量
1) UserDao
/**
* 通过条件查询-用户表记录数
* @param connection
* @param userName
* @param userRole
* @return
* @throws Exception
*/
public int getUserCount(Connection connection, String userName, int userRole)throws Exception;
2) UserDaoImpl
count(*) 可以统计所有的行数,包括为null的行,*代表所有字段
count(1) 统计的是第一个子字段的行数,为null的行数 不统计
@Override
//通过用户名或者角色查询用户总数
public int getUserCount(Connection connection, String userName, int userRole)
throws Exception {
// TODO Auto-generated method stub
PreparedStatement preparedStatement = null;
ResultSet rs = null;
int count = 0;
if(connection != null){
//只通过名字或只通过角色
StringBuffer sql = new StringBuffer();
sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole = r.id");
List<Object> list = new ArrayList<Object>();//list为了存放参数(占位符)
if(!StringUtils.isNullOrEmpty(userName)){
sql.append(" and u.userName like ?");
list.add("%"+userName+"%");//%模糊查询,index=0
}
if(userRole > 0){
sql.append(" and u.userRole = ?");
list.add(userRole);//index=1
}
Object[] params = list.toArray();
System.out.println("sql ----> " + sql.toString());
rs = BaseDao.execute(connection, preparedStatement, rs, sql.toString(), params);
if(rs.next()){
count = rs.getInt("count");//从结果集获得最终数量
}
BaseDao.closeResource(null, preparedStatement, rs);
}
return count;
}
3) UserService
public int getUserCount(String queryUserName, int queryUserRole);
4) UserServiceImpl
@Override
//查询记录数
public int getUserCount(String queryUserName, int queryUserRole) {
// TODO Auto-generated method stub
Connection connection = null;
int count = 0;
System.out.println("queryUserName ---- > " + queryUserName);
System.out.println("queryUserRole ---- > " + queryUserRole);
try {
connection = BaseDao.getConnection();
count = userDao.getUserCount(connection, queryUserName,queryUserRole);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
BaseDao.closeResource(connection, null, null);
}
return count;
}
1.2 获取用户列表
1) UserDao
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize)throws Exception;
2) UserDaoImpl
count(*) 可以统计所有的行数,包括为null的行,*代表所有字段
count(1) 统计的是第一个子字段的行数,为null的行数 不统计
这里准备好每页的数据,最后由servlet根据pagesupport.java决定分页的index,输入进service层,再到dao
@Override
public List<User> getUserList(Connection connection, String userName,int userRole,int currentPageNo, int pageSize)
throws Exception {
// TODO Auto-generated method stub
//判断名字和角色
PreparedStatement pstm = null;
ResultSet rs = null;
List<User> userList = new ArrayList<User>();
if(connection != null){
StringBuffer sql = new StringBuffer();
sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");
List<Object> list = new ArrayList<Object>();
if(!StringUtils.isNullOrEmpty(userName)){
sql.append(" and u.userName like ?");
list.add("%"+userName+"%");
}
if(userRole > 0){
sql.append(" and u.userRole = ?");
list.add(userRole);
}
//在数据库中,分页使用limit startIndex,pageSize;
//1,5
//6,5
//11,5
sql.append(" order by creationDate DESC limit ?,?");
currentPageNo = (currentPageNo-1)*pageSize;
list.add(currentPageNo);
list.add(pageSize);
Object[] params = list.toArray();
System.out.println("sql ----> " + sql.toString());
rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
while(rs.next()){
User _user = new User();
_user.setId(rs.getInt("id"));
_user.setUserCode(rs.getString("userCode"));
_user.setUserName(rs.getString("userName"));
_user.setGender(rs.getInt("gender"));
_user.setBirthday(rs.getDate("birthday"));
_user.setPhone(rs.getString("phone"));
_user.setUserRole(rs.getInt("userRole"));
_user.setUserRoleName(rs.getString("userRoleName"));
userList.add(_user);
}
BaseDao.closeResource(null, pstm, rs);
}
return userList;
}
3) UserService
public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize);
4) UserServiceImpl
@Override
public List<User> getUserList(String queryUserName,int queryUserRole,int currentPageNo, int pageSize) {
// TODO Auto-generated method stub
Connection connection = null;
List<User> userList = null;
System.out.println("queryUserName ---- > " + queryUserName);
System.out.println("queryUserRole ---- > " + queryUserRole);
System.out.println("currentPageNo ---- > " + currentPageNo);
System.out.println("pageSize ---- > " + pageSize);
try {
connection = BaseDao.getConnection();
userList = userDao.getUserList(connection, queryUserName,queryUserRole,currentPageNo,pageSize);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
BaseDao.closeResource(connection, null, null);
}
return userList;
}
1.3 获取角色操作
作用:角色有下拉列表,因此要从数据库里取
1) RoleDao
public List<Role> getRoleList(Connection connection)throws Exception;
2) RoleDaoImpl
@Override
//取出role放在ArrayList里
public List<Role> getRoleList(Connection connection) throws Exception {
PreparedStatement pstm = null;
ResultSet rs = null;
List<Role> roleList = new ArrayList<Role>();
if(connection != null){
String sql = "select * from smbms_role";
Object[] params = {};
rs = BaseDao.execute(connection, pstm, rs, sql, params);
while(rs.next()){
//创建对象保存进去
Role _role = new Role();
_role.setId(rs.getInt("id"));
_role.setRoleCode(rs.getString("roleCode"));
_role.setRoleName(rs.getString("roleName"));
roleList.add(_role);
}
BaseDao.closeResource(null, pstm, rs);
}
return roleList;
}
3) RoleService
public List<Role> getRoleList();
4) RoleServicImpl
@Override
public List<Role> getRoleList() {
Connection connection = null;
List<Role> roleList = null;
try {
connection = BaseDao.getConnection();
roleList = roleDao.getRoleList(connection);
} catch (Exception e) {
e.printStackTrace();
}finally{
BaseDao.closeResource(connection, null, null);
}
return roleList;
}
2 用户显示的Servlet
1)获取用户前端的数据
//从前端获取数据
String queryUserName = request.getParameter("queryname");
String temp = request.getParameter("queryUserRole");
String pageIndex = request.getParameter("pageIndex");
int queryUserRole = 0;
2)判断请求是否需要执行,看参数的值判断
//2.获取用户列表
UserService userService = new UserServiceImpl();
List<User> userList = null;
//设置页面容量(写在配置文件里了)第一次走这个请求,一定是第一页
int pageSize = Constants.pageSize;
//当前页码
int currentPageNo = 1;
/**
* http://localhost:8090/SMBMS/userlist.do
* ----queryUserName --NULL
* http://localhost:8090/SMBMS/userlist.do?queryname=
* --queryUserName ---""
*/
System.out.println("queryUserName servlet--------"+queryUserName);
System.out.println("queryUserRole servlet--------"+queryUserRole);
System.out.println("query pageIndex--------- > " + pageIndex);
//查询为空的话赋值
if(queryUserName == null){
queryUserName = "";
}
if(temp != null && !temp.equals("")){
queryUserRole = Integer.parseInt(temp);//给查询赋值
}
if(pageIndex != null){
try{
currentPageNo = Integer.valueOf(pageIndex);
}catch(NumberFormatException e){
response.sendRedirect("error.jsp");
}
}
3)为了实现分页,需要计算当前页面和总页面,页面大小。
//3.获取用户的总数(上一页,下一页)---总数量(表)调用service层
int totalCount = userService.getUserCount(queryUserName,queryUserRole);
//总页数支持
PageSupport pages=new PageSupport();
pages.setCurrentPageNo(currentPageNo);
pages.setPageSize(pageSize);
pages.setTotalCount(totalCount);
int totalPageCount = pages.getTotalPageCount();//从分页支持中得到能写的数量
//4.控制首页和尾页
//如果页面小于1,就显示第一页的东西
if(currentPageNo < 1){
currentPageNo = 1;
}else if(currentPageNo > totalPageCount){
currentPageNo = totalPageCount;
}
4)用户列表展示
//5.获取用户列表展示
userList = userService.getUserList(queryUserName,queryUserRole,currentPageNo, pageSize);//一页的用户对象
request.setAttribute("userList", userList);//对应userlist.jsp里的userList
List<Role> roleList = null;
RoleService roleService = new RoleServiceImpl();
roleList = roleService.getRoleList();
request.setAttribute("roleList", roleList);
request.setAttribute("queryUserName", queryUserName);
request.setAttribute("queryUserRole", queryUserRole);
request.setAttribute("totalPageCount", totalPageCount);
request.setAttribute("totalCount", totalCount);
request.setAttribute("currentPageNo", currentPageNo);
6)返回前端
//6.返回前端
request.getRequestDispatcher("userlist.jsp").forward(request, response);