JavaWeb-项目实践总结
准备阶段
- 使用maven(项目构建管理工具)
- 数据库
- 静态文件(css,js,html,jsp…)
- 生成目录结构
- com.xxx.dao:存放dao类(专门与数据库交互)
- com.xxx.filter:存放filter类(过滤层),用于处理页面乱码以及拦截游客访问
- com.xxx.pojo:存放实体类(根据数据库) ORM 对象关系映射
- com.xxx.service:存放Servive类(业务逻辑)
- com.xxx.servlet:存放servlet类(页面重定向,跳转和任务转交Service层,完成功能)
- com.xxx.util:存放Utils类(工具类)
Tips:
过滤层
通过url能直接访问的路径为基本的首页和登录界面等共享界面,用户登录后的页面放在单独的路径并设置过滤层对非登录用户的直接访问进行拦截
目录结构
web.xml的过滤器设置:
SysFilter.java
public class SysFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
//转为能够获取session得HttpServletRequest和HttpServletResponse
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//判断用户是否登录过(只有登录过才有Constant.USER_SESSION属性)
if (request.getSession().getAttribute(Constant.USER_SESSION)==null){
//为空则跳转至错误界面
response.sendRedirect(request.getContextPath()+"/error.jsp");
}
else {
filterChain.doFilter(req,resp);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
准备工具类(比如数据库的工具类)
db.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 connection,PreparedStatement preparedStatement,ResultSet resultSet,String sql,Object[] params) throws SQLException {
//预编译
preparedStatement = connection.prepareStatement(sql);
//可能查多个对象,占位符从1开始,数组从0开始
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i+1,params[i]);
}
resultSet = preparedStatement.executeQuery();
return resultSet;
}
//编写增\删\改公共类
public static int execute(Connection connection,PreparedStatement preparedStatement,String sql,Object[] params) throws SQLException {
//预编译
preparedStatement = connection.prepareStatement(sql);
//可能查多个对象,占位符从1开始,数组从0开始
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i+1,params[i]);
}
int updateRows = preparedStatement.executeUpdate();
return updateRows;
}
//释放资源
public static boolean release(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet){
boolean flag = true;
if (resultSet!=null){
try {
resultSet.close();
//GC回收
resultSet = null;
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
if (preparedStatement!=null){
try {
preparedStatement.close();
//GC回收
preparedStatement = null;
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
if (connection!=null){
try {
connection.close();
//GC回收
connection = null;
} catch (SQLException throwables) {
throwables.printStackTrace();
flag = false;
}
}
return flag;
}
}
自底向上
从底层开始写,一层一层向上调用,分析前端需求,需要根据什么信息(参数)获取数据库的什么信息/对象(返回值)
example
dao
接口:userDao,roleDao,...
实现:userDaoImpl,roleDaoImpl
service
接口:userService,roleService,...
实现:userServiceImpl,roleServiceImpl,...
example:
Model层
UserDao.java
public interface UserDao {
//得到要登录的用户
public User getLoginUser(Connection connection,String userCode,String password);
//修改当前用户密码
public int updatePwd(Connection connection,int id,String password) throws SQLException;
//根据用户名和用户角色查询个数
public int getCount(Connection connectin,String userName,int userRole) throws SQLException;
//根据用户名或用户角色查询用户
public List<User> getUserList(Connection connection,String userName,int userRole,int currentPageNo,int pageSize) throws SQLException;
//添加用户
public boolean addUser(Connection connection,User user) throws SQLException;
//根据UserCode判断用户是否存在
public boolean userCodeExist(Connection connection,String userCode) throws SQLException;
}
UserDaoImpl.java
public class UserDaoImp1 implements UserDao{
//从数据库返回查到的user
public User getLoginUser(Connection connection, String userCode,String password) {
PreparedStatement pst = null;
ResultSet rs = null;
User user = null;
if (connection!=null){
String sql = "select * from smbms_user where userCode=? and userPassword=?";
Object[] params = {userCode,password};
try {
rs = BaseDao.execute(connection, pst, 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.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getDate("modifyDate"));
}
BaseDao.release(connection,pst,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return user;
}
......
}
UserService.java
public interface UserService {
//用户登录
public User login(String userCode, String Password);
//根据user id 修改密码
public boolean updatePwd(int id,String password);
//查询记录数
public int getUserCount(String userName,int userRole);
//通过用户名和用户角色返回用户列表
public List<User> getUserList(String queUserName,int queUserRole,int currentPageNo,int pageSize);
//添加用户
public boolean addUser(User user);
//更具userCode判断用户是否存在
public boolean userCodeExist(String userCode) throws SQLException;
}
UserServiceImpl.java
public class UserServiceImp1 implements UserService{
//业务层都会调用dao层所以需要引入dao层
private UserDao userDao;
public UserServiceImp1(){
userDao = new UserDaoImp1();
}
//登录的业务层逻辑,返回登录用户
public User login(String userCode, String password) {
User user = new User();
Connection conn = BaseDao.getConnection();
//通过业务层,调用具体的数据库操作
User loginUser = userDao.getLoginUser(conn,userCode,password);
//关闭资源
BaseDao.release(conn,null,null);
return loginUser;
}
......
}
Controller层
LoginServlet.java 控制页面跳转与任务转接service层
public class LoginServlet extends HttpServlet {
//Servlet:控制层,调用业务层代码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入LoginServlet...");
//获取用户名和密码
String userName = req.getParameter("userCode");
String userPassword = req.getParameter("userPassword");
//和数据库中的用户密码进行对比,调用业务层
UserServiceImp1 userService = new UserServiceImp1();
User loginUser = userService.login(userName, userPassword);//这里已经把登录的人查出来了
if (loginUser!=null){//查有此人,可以登录
//将用户的信息放入session中
req.getSession().setAttribute(Constant.USER_SESSION,loginUser);
//跳转到内部主页
resp.sendRedirect("jsp/frame.jsp");
}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);
}
}
View层
将后端的数据放回前端展示给用户看
Servlet的复用技巧
如果每个可能的功能模块都需要一个servlet的话,servlet就太多了,可以配合前端的隐藏域进行servlet的复用
example
前端的一些控件统一一提交给/jsp/user.do
完整路径:http://localhost:8080/jsp/user.do?method=query&…
在后端中通过method属性获取具体的方法,加以区分
在复用的servlet中对method进行判断
//实现servlet复用,将方法提出来(跟前端隐藏域结合)
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if (method.equals("savepwd")&&method!=null){
this.updatePwd(req,resp);
}else if(method.equals("pwdmodify")&&method!=null){
this.pwdModify(req,resp);
}else if (method.equals("query")&&method!=null){
this.query(req,resp);
}else if (method.equals("add")&&method!=null){
this.add(req,resp);
}else if(method.equals("getrolelist")&&method!=null){
this.getRoleList(req,resp);
}else if(method.equals("ucexist")&&method!=null){
this.userCodeExist(req,resp);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp){...]
public void updatePwd(HttpServletRequest req, HttpServletResponse resp){...}
public void pwdModify(HttpServletRequest req, HttpServletResponse resp){...}
...
}
动态的SQL语句
此时前端传回来的参数是不确定的,所以需要动态地在后端中根据前端传回的参数来查找数据库
//根据分页信息和用户名以及角色,返回指定页面大小的用户列表
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws SQLException {
PreparedStatement pstm = null;
StringBuffer sql = new StringBuffer();//这里需要判断userName和userRole是否为空来动态拼接字符串(sql语句)
ResultSet rs = null;
List<User> userlist = new ArrayList<User>();//用list存放参数
int count = 0;
if (connection!=null) {
ArrayList<Object> list = new ArrayList<Object>();
//最基本的sql语句(那两个参数为空的情况下,查询全部的用户)
sql.append("select u.*,r.roleName as userRoleName from `smbms_user` as `u`,`smbms_role` as `r` "
"where u.userRole = r.id");
//如果userName不为空则,添加查询该userName的sql语句,这里用模糊查询用list存放
if (!StringUtils.isNullOrEmpty(userName)) {
sql.append(" and u.username like ?");
list.add("%" + userName + "%");
}
//userRole同理
if (userRole > 0) {
sql.append(" and u.userRole = ?");
list.add(userRole);
}
...
Object[] params = list.toArray();
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"));
_user.setModifyDate(rs.getDate("modifyDate"));
userlist.add(_user);
}
BaseDao.release(null,pstm,rs);
}
return userlist;
}
对数据库的增删改需要在业务层开启事务
public boolean addUser(User user) {
Connection connection = null;
boolean b = false;
try {
connection = BaseDao.getConnection();
//开启jdbc事务
connection.setAutoCommit(false);
b = userDao.addUser(connection, user);
connection.commit();
if (b){
System.out.println("add sucess");
}else {
System.out.println("add failed");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
try {
System.out.println("rollback-----------");
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}finally {
BaseDao.release(connection,null,null);
}
return b;
}