JavaWeb-SMBMS项目:
学习视频-狂神说JavaWeb:视频链接
JavaWeb-SMBMS项目
一、SMBMS
SMBMS模块
数据库架构
项目如何搭建?
考虑是不是用maven? jar包,依赖
二、项目搭建准备工作
1、搭建一个maven web 项目
-
补全maven项目结构
-
更新web.xml的配置版本
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> </web-app>
-
删除pom.xml中无用的东西
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tang</groupId> <artifactId>smbms</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>smbms Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> </project>
2、配置Tomcat
3、测试项目是否能够跑起来
4、导入项目中需要的jar包;
jsp,Servlet,mysql驱动jstl,stand…
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
5、创建项目包结构
6、编写实体类
- ROM映射:表-类映射
1、User类
package com.tang.pojo;
import java.util.Date;
public class User {
private Integer id;//id
private String userCode;//用户编码
private String userName;//用户名
private String userPassword;//用户密码
private Integer gender;//性别
private Date birthday;//出生日期
private String phone;//电话
private String address;//地址
private Integer userRole;//用户角色
private Integer createdBy;//创建者
private Date creationDate;//创建日期
private Integer modifyBy;//更新者
private Date modifyDate;//更新日期
private Integer age;//年龄
private String userRoleName;//用户角色名称
public User() {
}
public User(Integer id, String userCode, String userName,
String userPassword, Integer gender, Date birthday,
String phone, String address, Integer userRole,
Integer createdBy, Date creationDate, Integer modifyBy,
Date modifyDate, Integer age, String userRoleName) {
this.id = id;
this.userCode = userCode;
this.userName = userName;
this.userPassword = userPassword;
this.gender = gender;
this.birthday = birthday;
this.phone = phone;
this.address = address;
this.userRole = userRole;
this.createdBy = createdBy;
this.creationDate = creationDate;
this.modifyBy = modifyBy;
this.modifyDate = modifyDate;
this.age = age;
this.userRoleName = userRoleName;
}
public Integer getAge() {
return new Date().getYear() - birthday.getYear();
}
public String getUserRoleName() {
return userRoleName;
}
public void setUserRoleName(String userRoleName) {
this.userRoleName = userRoleName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getUserRole() {
return userRole;
}
public void setUserRole(Integer userRole) {
this.userRole = userRole;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Integer getModifyBy() {
return modifyBy;
}
public void setModifyBy(Integer modifyBy) {
this.modifyBy = modifyBy;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
}
2、Role类
package com.tang.pojo;
import java.util.Date;
public class Role {
private Integer id;
private String roleCode;
private String roleName;
private Integer createdBy;
private Date creationDate;
private Integer modifyBy;
private Date modifyDate;
public Role() {
}
public Role(Integer id, String roleCode,
String roleName, Integer createdBy,
Date creationDate, Integer modifyBy,
Date modifyDate) {
this.id = id;
this.roleCode = roleCode;
this.roleName = roleName;
this.createdBy = createdBy;
this.creationDate = creationDate;
this.modifyBy = modifyBy;
this.modifyDate = modifyDate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleCode() {
return roleCode;
}
public void setRoleCode(String roleCode) {
this.roleCode = roleCode;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Integer getModifyBy() {
return modifyBy;
}
public void setModifyBy(Integer modifyBy) {
this.modifyBy = modifyBy;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
}
3、Provider类
package com.tang.pojo;
import java.util.Date;
public class Provider {
private Integer id;//主键ID
private String proCode;//供应商编码
private String proName;//供应商名称
private String proDesc;//供应商供应商详细描述
private String proContact;//供应商联系人
private String proPhone;//供应商电话
private String proAddress;//供应商地址
private String proFax;//供应商传真
private Integer createdBy;//创建者(userId)
private Date creationDate;//创建日期
private Integer modifyBy;//更新者
private Date modifyDate;//更新日期(userId)
public Provider() {
}
public Provider(Integer id, String proCode,
String proName, String proDesc,
String proContact, String proPhone,
String proAddress, String proFax,
Integer createdBy, Date creationDate,
Integer modifyBy, Date modifyDate) {
this.id = id;
this.proCode = proCode;
this.proName = proName;
this.proDesc = proDesc;
this.proContact = proContact;
this.proPhone = proPhone;
this.proAddress = proAddress;
this.proFax = proFax;
this.createdBy = createdBy;
this.creationDate = creationDate;
this.modifyBy = modifyBy;
this.modifyDate = modifyDate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProCode() {
return proCode;
}
public void setProCode(String proCode) {
this.proCode = proCode;
}
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName = proName;
}
public String getProDesc() {
return proDesc;
}
public void setProDesc(String proDesc) {
this.proDesc = proDesc;
}
public String getProContact() {
return proContact;
}
public void setProContact(String proContact) {
this.proContact = proContact;
}
public String getProPhone() {
return proPhone;
}
public void setProPhone(String proPhone) {
this.proPhone = proPhone;
}
public String getProAddress() {
return proAddress;
}
public void setProAddress(String proAddress) {
this.proAddress = proAddress;
}
public String getProFax() {
return proFax;
}
public void setProFax(String proFax) {
this.proFax = proFax;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Integer getModifyBy() {
return modifyBy;
}
public void setModifyBy(Integer modifyBy) {
this.modifyBy = modifyBy;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
}
4、Bill类
package com.tang.pojo;
import java.math.BigDecimal;
import java.util.Date;
public class Bill {
private Integer id;//主键ID
private String billCode;//账单编码
private String productName;//商品名称
private String productDesc;//商品描述
private String productUnit;//商品单位
private BigDecimal productCount;//商品数量
private BigDecimal totalPrice;//商品总额
private Integer isPayment;//是否支付(1:未支付 2:已支付)
private Integer createdBy;//创建者(userId)
private Date creationDate;//创建时间
private Integer modifyBy;//更新者(userId)
private Date modifyDate;//更新时间
private Integer providerId;//供应商ID
private String providerName;//供应商名称
public Bill() {
}
public Bill(Integer id, String billCode,
String productName, String productDesc,
String productUnit, BigDecimal productCount,
BigDecimal totalPrice, Integer isPayment,
Integer createdBy, Date creationDate,
Integer modifyBy, Date modifyDate,
Integer providerId, String providerName) {
this.id = id;
this.billCode = billCode;
this.productName = productName;
this.productDesc = productDesc;
this.productUnit = productUnit;
this.productCount = productCount;
this.totalPrice = totalPrice;
this.isPayment = isPayment;
this.createdBy = createdBy;
this.creationDate = creationDate;
this.modifyBy = modifyBy;
this.modifyDate = modifyDate;
this.providerId = providerId;
this.providerName = providerName;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBillCode() {
return billCode;
}
public void setBillCode(String billCode) {
this.billCode = billCode;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductDesc() {
return productDesc;
}
public void setProductDesc(String productDesc) {
this.productDesc = productDesc;
}
public String getProductUnit() {
return productUnit;
}
public void setProductUnit(String productUnit) {
this.productUnit = productUnit;
}
public BigDecimal getProductCount() {
return productCount;
}
public void setProductCount(BigDecimal productCount) {
this.productCount = productCount;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getIsPayment() {
return isPayment;
}
public void setIsPayment(Integer isPayment) {
this.isPayment = isPayment;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Integer getModifyBy() {
return modifyBy;
}
public void setModifyBy(Integer modifyBy) {
this.modifyBy = modifyBy;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
public Integer getProviderId() {
return providerId;
}
public void setProviderId(Integer providerId) {
this.providerId = providerId;
}
}
7、编写基础公共类
1、数据库配置文件
- (mysql 5和8有差异)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false
username=root
password=root
2、编写数据库的公共类
package com.tang.dao;
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 (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//编写查询公共方法
public static ResultSet executeQuery(
Connection connection,PreparedStatement preparedStatement,ResultSet resultSet,
String sql,Object[] params) throws SQLException {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i+1,params[i]);
}
resultSet = preparedStatement.executeQuery();
return resultSet;
}
//编写增删改公共方法
public static int executeUpdate(
Connection connection,PreparedStatement preparedStatement,
String sql,Object[] params) throws SQLException {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i+1,params[0]);
}
return preparedStatement.executeUpdate();
}
//释放资源
public static Boolean closeResource(Connection connection,
PreparedStatement preparedStatement,
ResultSet resultSet){
boolean flag = true;
if (resultSet!=null){
try {
resultSet.close();
//GC回收
resultSet = null;
} catch (SQLException e) {
e.printStackTrace();
flag=false;
}
}
if (preparedStatement!=null){
try {
preparedStatement.close();
//GC回收
preparedStatement = null;
} catch (SQLException e) {
e.printStackTrace();
flag=false;
}
}
if (connection!=null){
try {
connection.close();
//GC回收
connection = null;
} catch (SQLException e) {
e.printStackTrace();
flag=false;
}
}
return flag;
}
}
3、编写字符编码过滤器
package com.tang.filter;
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() {
}
}
xml中注册
<!-- 字符编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.tang.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
8、导入静态资源(smbms静态资源)
三、登录功能实现
页面实现逻辑/流程
1、编写前端页面
前端页面直接使用已有的,我们主要编写网页背后的执行代码
2、设置首页
<!--设置欢迎页/首页-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
3、编写Dao层用户登陆的接口
-
创建一个UserDao接口,然后我们按照"面向接口编程"的原则去接口UserDaoImpl中实现这个接口中的方法
-
使用面向接口编程的好处就在与我们在接口中只需要定义方法,而不需要实现方法,整个结构和思路都很清晰
-
其次就是将设计和实现分离,保证了设计专注于设计,实现专注于实现
-
package com.tang.dao.user;
import com.tang.pojo.User;
import java.sql.Connection;
import java.sql.SQLException;
public interface UserDao {
//得到要登录的用户
public User getLoginUser(Connection connection,String userCode) throws SQLException;
}
4、编写Dao接口的实现类
package com.tang.dao.user;
import com.tang.dao.BaseDao;
import com.tang.pojo.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDaoImpl implements UserDao{
//得到要登录的用户
@Override
public User getLoginUser(Connection connection, String userCode) throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
if (connection!=null) {
String sql = "select * from smbms_user where userCode=?";
Object[] params = {userCode};
rs = BaseDao.executeQuery(connection, ps, 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.getDate("creationDate"));
user.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getDate("modifyDate"));
}
BaseDao.closeResource(null, ps, rs);
}
return user;
}
}
5、编写业务层接口
package com.tang.service;
import com.tang.pojo.User;
public interface UserService {
//用户登录
public User login(String userCode,String password);
}
6、业务层实现类
package com.tang.service;
import com.tang.dao.BaseDao;
import com.tang.dao.user.UserDao;
import com.tang.dao.user.UserDaoImpl;
import com.tang.pojo.User;
import java.sql.Connection;
import java.sql.SQLException;
public class UserServiceImpl implements UserService{
//业务层都会调用dao层,所以我们要引入Dao层;
private UserDao userDao;
public UserServiceImpl() {
userDao = new UserDaoImpl();
}
//用户登录
@Override
public User login(String userCode, String password) {
Connection connection = null;
User user = null;
try {
connection = BaseDao.getConnection();
//通过业务层调用对应的具体的数据库操作
user = userDao.getLoginUser(connection, userCode);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(connection,null,null);
}
return user;
}
}
测试是否能够成功运行
@Test
public void test(){
UserServiceImpl userService = new UserServiceImpl();
User admin = userService.login("admin","111111");
System.out.println(admin.getUserPassword());
}
7、编写servlet
- 首先导入我们也用到的JSP页面
-
其中frame.jsp是登陆成功之后跳转的页面,而common中是页面的头部和底部
-
注意:我们在编写servlet和注册servlet的时候一定要注意我们使用的前端页面上面写的地址,为了不出错最后应是与前端页面上写的地址保持一致;其次就是注意前端使用的JSP内置对象和EL表达式,我们在后端需要使用对应的变量名,否则是取不到值的
servlet编写
package com.tang.servlet.user;
import com.tang.pojo.User;
import com.tang.service.UserService;
import com.tang.service.UserServiceImpl;
import com.tang.util.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 LoginServlet extends HttpServlet {
//Servlet:控制层,调用业务层代码
UserService userService;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("LoginServlet--start...");
String userCode = req.getParameter("userCode");
String userPassword = req.getParameter("userPassword");
//和数据库中的密码进行对比,调用业务层
userService = new UserServiceImpl();
User user = userService.login(userCode, userPassword);
/* if (user!=null){//查有此人,可以登录
//将用户的信息放到session中
req.getSession().setAttribute(Constants.USER_SESSION,user);
resp.sendRedirect(req.getContextPath()+"/jsp/frame.jsp");
}else {//查无此人,无法登录
//转发回登录页面,顺带提示它,用户名或者密码错误
req.setAttribute("error","用户名或者密码错误");
req.getRequestDispatcher("login.jsp").forward(req,resp);
} */
if (user!=null){//查有此人
if (user.getUserPassword().equals(userPassword)){//密码正确,可以登录
req.getSession().setAttribute(Constants.USER_SESSION,user);
resp.sendRedirect(req.getContextPath()+"/jsp/frame.jsp");
}else {//密码错误,无法登录
//转发回登录页面,顺带提示它,密码错误
req.setAttribute("error","密码错误");
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
}else {//查无此人,无法登录
//转发回登录页面,顺带提示它,用户名不存在
req.setAttribute("error","用户名不存在");
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
8、注册servlet
<!--注册登陆的servlet-->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.tang.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
注意:这里的映射与我们使用的前端页面表单提交的action要保持一致
9、测试访问,确保以上功能成功!
四、注销功能实现
思路:移除session,返回登录页面
1、编写servlet
package com.tang.servlet.user;
import com.tang.util.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);
resp.sendRedirect(req.getContextPath()+"/login.jsp");//返回登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2、注册servlet
<!-- 注销登录 -->
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>com.tang.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>
五、登录拦截优化
1、编写SysFilter过滤器
package com.tang.filter;
import com.tang.pojo.User;
import com.tang.util.Constants;
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 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(req.getContextPath()+"/error.jsp");
}
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
2、注册过滤器
<!-- 登录拦截过滤器 -->
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.tang.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
</filter-mapping>
<!-- 请求转发拦截,上面的拦截对转发的 /jsp/* 无效 -->
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
<!-- 请求转发拦截 -->
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
测试,登录,注销,权限,都要保证OK!
六、密码修改
1、导入前端素材
2、写项目,建议从底层向上写
3、UserDao接口
//修改当前用户密码
public int UpdatePwd(Connection connection,int id,String password) throws SQLException;
4、UserDao接口实现
//修改当前用户密码
@Override
public int UpdatePwd(Connection connection, int id, String password) throws SQLException {
PreparedStatement ps = null;
int execute = 0;
if (connection != null) {
String sql = "update smbms_user set userPassword = ? where id = ?";
ps = connection.prepareStatement(sql);
Object[] params = {password, id};
execute = BaseDao.executeUpdate(connection, ps, sql, params);
BaseDao.closeResource(null, ps, null);
}
return execute;
}
5、UserService接口
//根据用户id修改密码
public boolean updatePwd(int id, String password);
6、UserService接口实现
//根据用户id修改密码
@Override
public boolean updatePwd(int id, String password) {
Connection conn = null;
boolean flag = false;
//修改密码
try {
conn = BaseDao.getConnection();
if (userDao.UpdatePwd(conn,id,password)>0){
flag = true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(conn,null,null);
}
return flag;
}
7、UserServlet编写
package com.tang.servlet.user;
import com.tang.pojo.User;
import com.tang.service.UserService;
import com.tang.service.UserServiceImpl;
import com.tang.util.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 UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从session里面拿ID;
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
boolean flag = false;
if (o != null && newpassword != null && newpassword.length() != 0) {
UserService userService = new UserServiceImpl();
User user = (User) o;
flag = userService.updatePwd(user.getId(), newpassword);
if (flag) {
req.setAttribute("message", "密码修改成功,请重新登录!");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
//密码修改成功,移除当前session
req.getSession().removeAttribute(Constants.USER_SESSION);
} else {
req.setAttribute("message", "密码修改失败!");
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}
} 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);
}
}
8、UserServlet注册
<!-- 修改当前用户密码 -->
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.tang.servlet.user.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/jsp/user.do</url-pattern>
</servlet-mapping>
9、测试
bug1:
//1、在编写servlet的时候,要判断前端传过来的新密码是否为空,这里ZB用了一个工具类,但是这个工具类是isNullOrEmpty,即它的作用判断"是空",所以使用的时候注意在前面加上一个"!"
//或者我们就是要常见的方法:newpassword!=null&&newpassword.length!=0
if (user!=null && !StringUtils.isNullOrEmpty(newpassword))
bug2:
//2、在编写BaseDao即基本公共数据库操作方法的时候,设置PreparedStatement对象中sql占位符的值时要注意
//PreparedStatement的占位符index从1开始,而数组的下标从0开始,所以我们使用的i=1,但是要注意控制循环次数的时候使用的是params.length,所以我们需要取"=",否则数组中的参数是取不完的,取不完就会出现SQL错误
for (int i=0;i<= params.length;i++){//循环遍历参数数组,并将参数设入SQL中
pstmt.setObject(i+1,params[i]);//注意:数组的index从0开始,而PreparedStatement中设置占位符的值的index从1开始
}
bug3:
//前端页面上,编写的时候要求输入旧密码,但是实际测试的时候输入旧密码有BUG,我们直接不使用输入旧密码,使用新密码+重复新密码输入框来修改密码
//但是前端使用的JS控制了提交表单的按钮,即需要3个输入框输入都满足要求的时候才能提交表单数据,所以我们需要把判断旧密码输入框的判断语句注释了
//这样才能只通过新密码+重复新密码实现密码修改
saveBtn.on("click",function(){
oldpassword.blur();
newpassword.blur();
rnewpassword.blur();
// oldpassword.attr("validateStatus") == "true"
// &&
if( newpassword.attr("validateStatus") == "true"
&& rnewpassword.attr("validateStatus") == "true"){
if(confirm("确定要修改密码?")){
$("#userForm").submit();
}
}
});
10、优化UserServlet代码,实现复用
package com.tang.servlet.user;
import com.tang.pojo.User;
import com.tang.service.UserService;
import com.tang.service.UserServiceImpl;
import com.tang.util.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 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);
}
//修改密码
public void updatePwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从session里面拿ID;
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
boolean flag = false;
if (o != null && newpassword != null && newpassword.length() != 0) {
UserService userService = new UserServiceImpl();
User user = (User) o;
flag = userService.updatePwd(user.getId(), newpassword);
if (flag) {
req.setAttribute("message", "密码修改成功,请重新登录!");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
//密码修改成功,移除当前session
req.getSession().removeAttribute(Constants.USER_SESSION);
} else {
req.setAttribute("message", "密码修改失败!");
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}
} else {
req.setAttribute("message", "新密码有问题!");
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}
}
}
通过测试,功能完全相同,且修改密码正确!
七、优化密码修改,使用Ajax
1、导入fastjson依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2、js中Ajax代码
oldpassword.on("blur",function(){
$.ajax({
type:"GET",
url:path+"/jsp/user.do",
data:{method:"pwdmodify",oldpassword:oldpassword.val()},
//上面两句话等价于:
// path+/jsp/user.do?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);
}
});
}).on("focus",function(){
validateTip(oldpassword.next(),{"color":"#666666"},"* 请输入原密码",false);
});
3、设置session过期时间
<!-- 默认session过期时间:真实过期时间 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
4、后台代码修改
package com.tang.servlet.user;
import com.alibaba.fastjson.JSONArray;
import com.mysql.jdbc.StringUtils;
import com.tang.pojo.User;
import com.tang.service.UserService;
import com.tang.service.UserServiceImpl;
import com.tang.util.Constants;
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;
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);
}else if (method != null && method.equals("pwdmodify")){
this.pwdmodify(req, resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
//修改密码
public void updatePwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从session里面拿ID;
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");
boolean flag = false;
if (o != null && newpassword != null && newpassword.length() != 0) {
UserService userService = new UserServiceImpl();
User user = (User) o;
flag = userService.updatePwd(user.getId(), newpassword);
if (flag) {
req.setAttribute("message", "密码修改成功,请重新登录!");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
//密码修改成功,移除当前session
req.getSession().removeAttribute(Constants.USER_SESSION);
} else {
req.setAttribute("message", "密码修改失败!");
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}
} else {
req.setAttribute("message", "新密码有问题!");
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}
}
//验证旧密码,session中有旧密码
public void pwdmodify(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//从session中拿到id
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = req.getParameter("oldpassword");
//万能的map
HashMap<String, String> resultMap = new HashMap<>();
if (o==null){//session失效了,session过期了
resultMap.put("result","sessionerror");
}else if (StringUtils.isNullOrEmpty(oldpassword)){//输入密码为空
resultMap.put("result","error");
}else {
//session中用户密码
String userPassword = ((User) o).getUserPassword();
if (oldpassword.equals(userPassword)){//密码输入正确
resultMap.put("result","true");
}else {//密码输入错误
resultMap.put("result","false");
}
}
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
//JSONArray 阿里巴巴的JSON工具类,转换格式
out.write(JSONArray.toJSONString(resultMap));
out.flush();
out.close();
}
}
八、用户管理实现
思路:
1、导入分页的工具类
package com.tang.util;
public class PageSupport {
//当前页码-来自于用户输入
private int currentPageNo = 1;
//总数量(表)
private int totalCount = 0;
//页面容量
private int pageSize = 0;
//总页数-totalCount/pageSize(+1)
private int totalPageCount = 1;
public int getCurrentPageNo() {
return currentPageNo;
}
//OOP三大特性:封装(属性私有,get/set,在set中限定一些不安全的情况)
public void setCurrentPageNo(int currentPageNo) {
if (currentPageNo > 0) {
this.currentPageNo = currentPageNo;
}
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
if (totalCount > 0) {
this.totalCount = totalCount;
//设置总页数
this.setTotalPageCountByRs();
}
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
if (pageSize > 0) {
this.pageSize = pageSize;
}
}
public int getTotalPageCount() {
return totalPageCount;
}
public void setTotalPageCount(int totalPageCount) {
this.totalPageCount = totalPageCount;
}
public void setTotalPageCountByRs() {
if (this.totalCount % this.pageSize == 0) {
this.totalPageCount = this.totalCount / this.pageSize;
} else if (this.totalCount % this.pageSize > 0) {
this.totalPageCount = this.totalCount / this.pageSize + 1;
} else {
this.totalPageCount = 0;
}
}
}
-
OOP的3大特性:封装、继承、多态
-
其中封装 = 属性私有+属性的get/set() + 在set中限制一些不安全的赋值操作(这一步可以留到service层再做,但是在封装的时候做更好,这样减少了service层的代码,且体现了封装的特性)
2、用户列表页面导入
导入jsp
分析:
-
Dao层使用聚合函数COUNT(*)查询用户表一共多少条记录
-
service层用于统计总共有多少条数据
-
servlet层用于向前端返回总共的数据条数
3、获取用户数量
1、UserDao
//查询用户总数
public int getUserCount(Connection connection,String userName,int userRole) throws SQLException;
2、UserDaoImpl
//根据 用户名或角色查询用户数【最难理解的sql】
@Override
public int getUserCount(Connection connection, String userName, int userRole) throws SQLException {
PreparedStatement ps = 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");
ArrayList<Object> list = new ArrayList<>();//存放我们的参数
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
}
//怎么把list转换为数组
Object[] params = list.toArray();
System.out.println("UserDaoImpl->getUserCount:"+sql.toString());//输出最后完整的sql语句
rs = BaseDao.executeQuery(connection, ps, rs, sql.toString(), params);
if (rs.next()){
count = rs.getInt("count");//从结果集中获取最终的数量
}
BaseDao.closeResource(null,ps,rs);
}
return count;
}
注意回顾知识点:
-
StringBuffer类:一个专门用来弥补String内容不可修改的类,调用这个类对象的append()可以实现在字符串的末尾加上新字符串且不会产生新的字符串对象(String对象的拼接操作其实在底层就是产生了新的String对象)
-
使用List集合来存储参数,这样做的好处就在于我们可以动态的向集合中添加参数,而不是像前面使用数组那样固定了数组长度;其实集合也是用来弥补数组长度不可修改的缺陷而出现的,使用集合存储数据即使数据很多也不会产生新的集合对象,而数组不一样,数组一经创建长度就固定了;而针对上面要实现的需求我们不知道到底前端要进行哪一种操作,所以我们不能定义一个定长的数组,即使按照最大需求量定义数组,虽然可以满足要求,但是在不能充分使用的时候就是资源的浪费
-
上面使用的动态的拼接SQL语句的做法很明智:既使用了StringBuffer对象控制SQL语句在提交之前可变,又使用了List集合来存储参数,在提交的时候才将其转为数组
3、UserService
//查询记录数
public int getUserCount(String userName,int userRole);
4、UserServiceImpl
//查询记录数
@Override
public int getUserCount(String userName, int userRole) {
Connection conn = null;
int count = 0;
try {
conn = BaseDao.getConnection();
count = userDao.getUserCount(conn, userName, userRole);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(conn,null,null);
}
return count;
}
5、测试
@Test
public void test(){
UserService userService = new UserServiceImpl();
int count = userService.getUserCount(null, 1);
System.out.println(count);
}
4、获取用户列表
1、UserDao
//根据条件查询 -> UserList
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo,int pageSize) throws SQLException;
2、UserDaoImpl
//根据条件查询 -> UserList
@Override
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
List<User> userList = new ArrayList<>();
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<>();//存放我们的参数
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
}
//在数据库中,分页使用 limit startIndex,pageSize;总数
//当前页(当前页-1)*页面大小
//0,5 1 0 0~4
//6,5 2 5 5~9
//10,5 3 10 10~14
sql.append(" order by u.creationDate desc limit ?,?");//降序和分页
currentPageNo=(currentPageNo-1)*pageSize;
list.add(currentPageNo);
list.add(pageSize);
//怎么把list转换为数组
Object[] params = list.toArray();
System.out.println("UserDaoImpl->getUserList:"+sql.toString());//输出最后完整的sql语句
System.out.println("UserDaoImpl->getUserList:"+ Arrays.toString(params));//输出最后完整的sql语句
rs = BaseDao.executeQuery(connection, ps, 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,ps,rs);
}
return userList;
}
3、UserService
//根据条件查询 -> UserList
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize);
4、UserServiceImpl
//根据条件查询 -> UserList
@Override
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) {
Connection conn = null;
List<User> userList = null;
try {
conn = BaseDao.getConnection();
userList = userDao.getUserList(conn, userName, userRole,currentPageNo,pageSize);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(conn,null,null);
}
return userList;
}
5、测试
@Test
public void test(){
UserService userService = new UserServiceImpl();
List<User> userList = userService.getUserList(null, 2, 1,5);
System.out.println(userList.size());
}
5、获取角色列表
- 为了职责统一,可以把角色的操作单独放在一个包中,和pojo类对应
1、RoleDao接口
package com.tang.dao.role;
import com.tang.pojo.Role;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public interface RoleDao {
//获取角色列表
public List<Role> getRoleList(Connection connection) throws SQLException;
}
2、RoleDaoImpl实现类
package com.tang.dao.role;
import com.tang.dao.BaseDao;
import com.tang.pojo.Role;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class RoleDaoImpl implements RoleDao{
//获取角色列表
@Override
public List<Role> getRoleList(Connection connection) throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
ArrayList<Role> roleList = new ArrayList<>();
if (connection!=null){
String sql = "select * from smbms_role";
Object[] params = {};
rs = BaseDao.executeQuery(connection, ps, 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,ps,rs);
}
return roleList;
}
}
3、RoleService接口
package com.tang.service.role;
import com.tang.pojo.Role;
import java.util.List;
public interface RoleService {
//获取角色列表
public List<Role> getRoleList();
}
4、RoleServiceImpl实现类
package com.tang.service.role;
import com.tang.dao.BaseDao;
import com.tang.dao.role.RoleDao;
import com.tang.dao.role.RoleDaoImpl;
import com.tang.pojo.Role;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class RoleServiceImpl implements RoleService{
//引入Dao
private RoleDao roleDao;
public RoleServiceImpl() {
this.roleDao = new RoleDaoImpl();
}
@Override
//获取角色列表
public List<Role> getRoleList() {
Connection conn = null;
List<Role> roleList = null;
try {
conn = BaseDao.getConnection();
roleList = roleDao.getRoleList(conn);
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(conn,null,null);
}
return roleList;
}
}
5、测试
@Test
public void test(){
RoleService roleService = new RoleServiceImpl();
List<Role> roleList = roleService.getRoleList();
System.out.println(roleList.size());
}
6、用户显示的servlet
- 从前端获取数据(查询)
- 对前端传递的参数值进行判断,来确定后端接收的值
- 为了实现分页,需要计算出:当前页面、页面大小、总用户数、总页面
- 用户列表展示
- 角色列表展示
- 将后端接收的值,再返回到前端
@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);
} else if (method != null && method.equals("pwdmodify")) {
this.pwdmodify(req, resp);
}else if (method != null && method.equals("query")) {
this.query(req, resp);
}
}
//重点、难点
public void query(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//查询用户列表
//从前端获取数据
String queryUserName = req.getParameter("queryname");
String temp = req.getParameter("queryUserRole");
String pageIndex = req.getParameter("pageIndex");
int queryUserRole = 0;
//对前端传递的参数值进行判断,来确定后端接收的值
//第一次走这个请求,一定是第一页,页面大小固定的,
int pageSize = 5;//可以把这个写到配置文件中,方便后期修改;
int currentPageNo = 1;
if (queryUserName==null){
queryUserName="";
}
if (temp!=null&& !temp.equals("")){
queryUserRole = Integer.parseInt(temp);//给查询赋值 0,1,2,3
}
if (pageIndex!=null){
currentPageNo = Integer.parseInt(pageIndex);
}
//获取用户的总数
UserService userService = new UserServiceImpl();
int totalCount = userService.getUserCount(queryUserName, queryUserRole);
//获取总页数
PageSupport pageSupport = new PageSupport();
pageSupport.setCurrentPageNo(currentPageNo);
pageSupport.setPageSize(pageSize);
pageSupport.setTotalCount(totalCount);
int totalPageCount = pageSupport.getTotalPageCount();//总页数
//控制首页和尾页
//如果页面小于1,就显示第一页的东西
if (currentPageNo<1){
currentPageNo=1;
}else if (currentPageNo>totalPageCount){
currentPageNo=totalPageCount;
}
//获取用户列表
List<User> userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);
req.setAttribute("userList",userList);//返回前端的数据
//获取角色列表
RoleService roleService = new RoleServiceImpl();
List<Role> roleList = roleService.getRoleList();
req.setAttribute("roleList",roleList);//返回前端的数据
//返回前端的数据
req.setAttribute("totalCount",totalCount);
req.setAttribute("currentPageNo",currentPageNo);
req.setAttribute("totalPageCount",totalPageCount);
req.setAttribute("queryUserName",queryUserName);
req.setAttribute("queryUserRole",queryUserRole);
//返回前端
req.getRequestDispatcher("userlist.jsp").forward(req,resp);
}
7、测试
-
小黄鸭调试法:自言自语。
-
增删改自行补充,其他模块自行补充,方法相似
九、项目感悟
- 项目亮点/技巧/学习点
1、在前端使用EL表达式取值
-
前端jsp页面中,使用EL表达式
${error}
取后端传递的参数 -
如果后端没有传递,将不显示
2、在session中存储用户的全部信息
在用户登陆成功的时候,从数据库中将用户的全部信息存到session中,这就便于后面我们需要使用这个用户的某些信息的时候,不用再去查询数据库,而直接从session中获取用户的信息。
用途:
-
修改密码的时候使用Ajax与session中User对象的password做对比
-
使用过滤器,在每一次用户发起请求的时候都去查看用户是否登陆,保证数据安全
-
用session控制用户最长在线时间,只要长时间没操作将自动注销登陆
-
注销功能,直接将session中用户对象属性删除即可配合过滤器将用户注销
-
...
3、SQL语句的动态拼接
-
在实现用户管理功能的模块中,首次用到了StringBuffer来实现动态拼接SQL语句,用List集合来实现动态存储ps对象所需要的参数数组的功能
-
StringBuffer提供动态拼接SQL语句的功能,使得我们可以在基础的SQL语句上加上独特的筛选条件
-
集合List通过存储ps对象所需要的参数数组的功能,使得不管我们要在后面添加多少筛选条件都只是用一个集合List存储,在最后传输的时候调用List.toArray()即可将其转为数组
-
4、某一功能的开发流程
-
要在前端实现一个功能,我们需要按照dao-->service-->servlet-->JSP的顺序来开发
-
在写代码之前先进行架构分析,划分模块→分析流程
5、在项目中多复用,少创建
-
本项目中,我们复用了servlet
- 通过前端传递的指定参数名的值,调用同一个servlet中不同的方法(将实现多个功能的servlet独立封装为一个个的方法)
6、合理使用隐藏域
通过隐藏域来让前端向后端传递method参数的值,后端通过判断method的值决定调用servlet中的哪个方法
7、合理使用过滤器
合理使用过滤器,可以为后端服务器拦截:非法请求、垃圾请求、无效请求,也可以解决中文乱码问题
注意:在使用过滤器的时候,正常情况下我们只需要实现doFilter()方法,在方法的最后一定要放行,否则将一直拦截
chain.doFilter(req,resp);//过滤器放行
8、合理编写公共类BaseDao
-
在本项目中,在最开始我们就编写了一个BaseDao类,可以对所有表进行CRUD操作
-
这个类我们一共只定义了1个static代码块+4个方法
-
静态代码块用于初始化连接JDBC的四大参数
-
4个方法分别为
-
获取数据库连接对象
-
查询数据
-
修改数据
-
关闭资源
-
-
-
-
注意:这些方法之间不要出现相互调用的情况,我们应该在具体的对某一张表进行操作的时候再来调用这个类中的某些方法;且这些方法使用的数据库对象全部都需要从外部传递
9、各层功能单一,使得项目维护更高效
-
项目开步骤应该按照dao-->service-->servlet-->JSP的顺序来开发
-
在开发的时候我们应该保证开发的每一层只完成自己这一层应该有的功能
-
各层的功能遵循SpringMVC的划分:
-
dao层只专注与数据库交互
-
service层专注于完成业务逻辑编写
-
servlet层专注获取前端请求、调用service、和跳转视图
-
JSP专注于页面展示
-
-
各层之间的功能不要混用,各层之间的联系通过项目调用来构建
10、多利用"面向接口编程"的思想
- 在本项目中,不管是开发dao层还是开发service层,我们都使用了面向接口编程的思想
- 编写接口,编写继承接口的实现类;这样我们开发过程中就实现了设计和实现分离,整个项目的架构就很清晰
11、多测试
- 在开发中,我们每写完一个功能之后,就应该使用junit对刚刚写的代码进行测试,保证开发的稳步前进
- 在Dao层有SQL语句的地方我们最好是写一句输出SQL语句的代码,这样每次执行的时候我们都可以看到SQL语句具体是什么样的,也容易进行排错
12、细心
开发过程中往往出现bug的地方都很微小,但是就是微小才不容易发现,从而导致了程序报错
-
比如:SQL语句拼接时的空格问题
-
比如:for循环时等号取不取的问题
-
比如:sql.append(" and u.userRole = ?");中将u.userRole写成r.roleCode
13、小黄鸭调试法
- 传说中程序大师随身携带一只小黄鸭,在调试代码的时候会在桌上放上这只小黄鸭,然后详细地向鸭子解释每行代码
- 一边阐述代码的意图一边观察它实际上的意图并做调试,这两者之间的任何不协调会变得很明显,并且更容易发现自己的错误
- 类似的,有一种现象叫做cone of answers,这是一个常见的现象。你的朋友跑来问你一个问题,但是当他自己把问题说完,或者说到一半的时候就想出了答案走了,留下一脸茫然的你。是的,这个时候你就起到了那只小黄鸭的作用
总的来说,在你试图表述自己的想法的过程中,自然地在促使自己去整理思路,重新考虑问题
14、一些简写(背下来)
-
CRUD:crud是指在做计算处理时的增加(Create):sql中是insert、检索(Retrieve):sql中是select、更新(Update):sql中是update和删除(Delete):sql中是delete,几个单词的首字母简写,crud主要被用在描述软件系统中数据库或者持久层的基本操作功能
-
ACID:ACID,指数据库事务正确执行的四个基本要素的缩写,包含:
-
Atomicity(原子性,或称不可分割性):一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成
-
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
- 例如:转账前后总钱数不变。
-
Isolation(隔离性,又称独立性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离级别分为四种:
-
脏读:Read Uncommited(读未提交)即一个事务可以读取另一个未提交事务的数据;并发操作会导致脏读
-
不可重复读:Read Commited(读操作)即一个事务要等到另一个修改(update)事务提交后才能读取数据;解决脏读问题;并发操作会导致不可重复读
-
幻读:Repeatable Read(重复读)即开始读取数据(事务开启)时,不再允许修改(update)操作;解决不可重复读问题;并发操作会导致幻读(对应insert操作)
-
Serializable,序列化,最高的事务隔离级别,该级别下,事务串行化顺序执行;避免脏读、不可重复读与幻读;但是该级别效率低下,比较消耗数据库性能,一般不用。
-
-
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
-
- 一个支持事务(Transaction)的数据库,必须要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求
15、实际开发中,多用事务
-
在实际的开发中,CRUD操作应该都是用事务操作来提交,这是因为这4种操作在执行的时候都可能失败,所以为了安全,最好的解决方案就是使用事务机制编写代码
-
注意事务的使用位置:在try开始的时候开启事务,在业务逻辑完成的时候提交事务,在catch中回滚事务
16、开发手册
- 推荐<阿里巴巴开发手册>,主要就是规约我们开发过程中的规范问题,写代码的结构问题 —— 很重要