SMBMS系统开发
1.前期准备
时间是2020.6.28,先在狂神的群里下载到了源代码,本想学狂神直接部署在tomcat上直接运行,后来发现,貌似必须打包发布才能直接运行,于是开始进行调试。
- 首先是打开文件,由于没有maven文件,idea报了一堆找不到类的错误,在自动提示的帮助下,让idea自动导入的包,解决了问题
- 似乎是由于java文件版本不对,idea也自动更新了版本
- 无法执行数据库连接
衍生问题:数据的导入
衍生问题:问什么用类加载器来加载properties文件
通过这种方式能直接使用相对路径获取对应的配置文件,类加载器相关内容请看反射与注解
衍生问题:Class.forname()方法加载驱动类
Class.forName()方法
此方法意味着是:加载参数指定的类,并初始化它。
在jdbc连接数据库中的应用
为什么要执行Class.forName('驱动类名')方法:将驱动类的类文件加载到内存中,并且形成一个描述此驱动类结构的Class类实例,并初始化此驱动类,这样jvm就可以使用它了,这就是Class.forName()方法的含义。
在JDBC中 Class.forName(“com.mysql.jdbc.Driver”),如果换成getClass().getClassLoader().loadClass(“com.mysql.jdbc.Driver”),就不可以,因为它只是想JVM装载了Driver的类信息,但是没有实例化,也就不能执行相应的操作,因为Driver是需要被初始化才能被使用的。
Class.forName(className)装载的class已经被实例化,classLoader.loadClass().则只是将信息装载给JVM。
项目搭建准备
- 搭建一个maven web项目
-
配置tomcat
-
测试项目能否跑起来
-
导入jar包
-
创建项目包结构
-
编写实体类
ORM映射
-
编写基础公共类
- 数据库配置文件
- 编写数据库公共类
- 编写字符过滤器
- 导入静态资源
2.登录功能
- 编写前端页面
-
设置首页
<!--设置欢迎页面--> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list>
- 编写dao层登陆用户登录的接口
//得到登录用户 public User getLoginUser(Connection connection, String usercode) throws SQLException;
- 编写dao接口实现类
public class UserDaoImpl implements UserDao { @Override public User getLoginUser(Connection connection, String usercode) throws SQLException { PreparedStatement statement = null; ResultSet resultSet = null; User user = null; if (connection != null) { String sql = "select * from smbms_user where usercode =?"; Object[] params = {usercode}; resultSet = BaseDao.execute(connection, resultSet, statement, sql, params); if (resultSet.next()) { user = new User(); user.setId(resultSet.getInt("id")); user.setUserCode(resultSet.getString("userCode")); user.setUserName(resultSet.getString("userName")); user.setUserPassword(resultSet.getString("userPassword")); user.setGender(resultSet.getInt("gender")); user.setBirthday(resultSet.getDate("birthday")); user.setPhone(resultSet.getString("phone")); user.setAddress(resultSet.getString("address")); user.setUserRole(resultSet.getInt("userRole")); user.setCreatedBy(resultSet.getInt("createdBy")); user.setCreationDate(resultSet.getTimestamp("creationDate")); user.setModifyBy(resultSet.getInt("modifyBy")); user.setModifyDate(resultSet.getTimestamp("modifyDate")); } BaseDao.closeResource(null,statement,resultSet); } return user; } }
- 编写业务层接口
//用户登录 public User login(String usercode,String password);
- 业务层实现类
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; connection = BaseDao.getConnection(); try { user = userDao.getLoginUser(connection, usercode); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } //对用户名的密码进行判断 if (password.equals(user.getUserPassword())){ return user; }else { return null; } } }
- 编写servlet
public class LoginServlet extends HttpServlet { /* * servlet:控制层,调用业务层 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("LoginServlet————start...."); //获取用户名和密码 String username = req.getParameter("userCode"); String password = req.getParameter("userPassword"); //和数据库中的密码进行对比,调用业务层 UserServiceImpl userService = new UserServiceImpl(); User user = userService.login(username, password); //用户存在 if (user!=null){ //将用户的信息放到session中; req.getSession().setAttribute(Constants.USER_SESSION,user); //跳转到内部主页 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); } }
- 注册servlet
- 测试访问,保证成功
衍生问题:为什么在basedao和service层中传递参数而不是直接new出来?
因为要考虑资源释放,baseDao的closeResource方法需要关闭开着的公共资源,比如connection,resultSet等,而且只关闭当前调用的资源,如果在basedao的getconnection现创建,就必须在本方法内关闭资源,那么关闭资源的结构就低于basedao的其他方法一级别。
正确的做法是由调用者提供资源,调用dao得到数据,调用者关闭资源,这样一个流程,在本项目中的流程就是usedao提供参数,usedao关闭资源,然后再由service调用usedao提供参数,service关闭资源
注意:connection由服务层提供,同样由服务层关闭
3.退出功能
由于退出只需要移除session中的用户,所以不需要操作数据库也就不同写dao和service,只需要在servlet中进行就好
- logoutservlet
public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 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); } }
- 注册xml
<servlet> <servlet-name>logoutServlet</servlet-name> <servlet-class>com.zhaox.servlet.userServlet.LogoutServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>logoutServlet</servlet-name> <url-pattern>/jsp/logout.do</url-pattern> </servlet-mapping>
衍生问题:注册xml中的路径与前端显示不一致
前端所展现的跳转页面的路径,应该完全与xml中注册的一致,否则会造成404错误
登陆拦截优化
- 编写一个过滤器
public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//从session中获取用户,注意此处getAttribute中输入的是字符串
User user = (User)req.getSession().getAttribute(Constants.USER_SESSION);
if(user==null){
//req.getContextPath代表当前目录
resp.sendRedirect(req.getContextPath()+"/error.jsp");
}else {
filterChain.doFilter(servletRequest,servletResponse);
}
}
@Override
public void destroy() {
}
}
- 注册
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.zhaox.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
4.密码修改功能
做一个项目功能,都要从底层往上写,建楼要从下往上建,那这个“从下往上“是指什么意思呢。
MVC的结构层:"与数据库进行交互的“Dao层——”专心于业务的“Service层——”负责传话和页面跳转的“Servlet层
所以写代码要先从Dao开始,向上方写,在开始敲键盘时要先想好要做什么。
- 先写接口
//修改用户密码 public int updatePwd(Connection connection, int id ,int password) throws SQLException;
- 再写接口实现
- 要小心,传过来的参数再上一层可能忘了传,所以要先做个判断,加个if判断连接存不存在之类的
- 在这里再仔细思考一下,basedao是不做任何新东西的创建的,因为要把创建的东西关闭,以此类推:最底层的东西是不会新建的,都是传过来的参数,在传过来的的地方做关闭处理!
//修改用户密码 @Override public int updatePwd(Connection connection, int id, int password) throws SQLException { PreparedStatement preparedStatement = null; String sql = "UPDATE smbms_user set userPassword = ? where id = ?"; Object params[] = {password,id}; int execute = 0; if (connection!=null){ execute = BaseDao.execute(connection, preparedStatement, sql, params); } return execute; }
- 写service层接口和他的实现类
//根据id修改密码 public boolean updatePwd( int id , String password) ;
@Override public boolean updatePwd(int id, String password) { boolean flag = false; Connection connection = null; try { connection = BaseDao.getConnection(); if (userDao.updatePwd(connection,id,password)>0){ flag = true; } } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } return flag; }
- 写servlet
注意,写servlet要先注册xml防止报错
同时,思考一个问题,我们是用旧密码来确定密码的,但是在改密码的地方却是用的id,我们该怎么得到id呢?
请看上面的登陆功能模块,我们在登陆时已经将用户的全部信息录入了session这时我们可以直接通过session得到用户的全部信息,在以后的开发生涯中,这也是我们的方法
-
代码复用
如何实现代码复用呢,userservlet里有很多操作,除了修改密码还有增删改查,我们可以把操作封装成方法,然后让get和post调用方法
```java
//封装好的方法
public void updatePwd(HttpServletRequest req, HttpServletResponse resp){
Object user = req.getSession().getAttribute(Constants.USER_SESSION);
String newpassword = req.getParameter("newpassword");<pre><code> //判断用户和输入的新密码是不是为空,只有两者皆为非空可以向下判断运行
if (user!=null&& !StringUtils.isNullOrEmpty(newpassword)){
UserServiceImpl userService = new UserServiceImpl();
boolean flag = userService.updatePwd(((User) user).getId(), newpassword);
if (flag){
req.setAttribute("message","修改密码成功,请退出,使用新密码登录");
//密码修改成功,移除当前session
req.getSession().removeAttribute(Constants.USER_SESSION);}else {
req.setAttribute("message","密码修改失败");
}
}else {
req.setAttribute("message","新密码有问题");
}
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
</code></pre>}
```
```java
//java的doget与dopost方法
@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);
}```
Ajax验证旧密码
先说一下整体思路:
首先,请先看修改密码的JS代码:
$(function(){
oldpassword = $("#oldpassword");
newpassword = $("#newpassword");
rnewpassword = $("#rnewpassword");
saveBtn = $("#save");
oldpassword.next().html("*");
newpassword.next().html("*");
rnewpassword.next().html("*");
oldpassword.on("blur",function(){
$.ajax({
type:"GET",
url:path+"/jsp/user.do",
data:{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);
});
newpassword.on("focus",function(){
validateTip(newpassword.next(),{"color":"#666666"},"* 密码长度必须是大于6小于20",false);
}).on("blur",function(){
if(newpassword.val() != null && newpassword.val().length > 6
&& newpassword.val().length < 20 ){
validateTip(newpassword.next(),{"color":"green"},imgYes,true);
}else{
validateTip(newpassword.next(),{"color":"red"},imgNo + " 密码输入不符合规范,请重新输入",false);
}
});
rnewpassword.on("focus",function(){
validateTip(rnewpassword.next(),{"color":"#666666"},"* 请输入与上面一致的密码",false);
}).on("blur",function(){
if(rnewpassword.val() != null && rnewpassword.val().length > 6
&& rnewpassword.val().length < 20 && newpassword.val() == rnewpassword.val()){
validateTip(rnewpassword.next(),{"color":"green"},imgYes,true);
}else{
validateTip(rnewpassword.next(),{"color":"red"},imgNo + " 两次密码输入不一致,请重新输入",false);
}
});
saveBtn.on("click",function(){
oldpassword.blur();
newpassword.blur();
rnewpassword.blur();
if(oldpassword.attr("validateStatus") == "true"
&&newpassword.attr("validateStatus") == "true"
&& rnewpassword.attr("validateStatus") == "true"){
if(confirm("确定要修改密码?")){
$("#userForm").submit();
}
}
});
});
这个js文件里封装了四个事件,分别是鼠标焦点在旧密码,新密码,重复新密码,和保存按钮上。让我们把注意力放在旧密码上:
这段代码,定义了焦点旧密码框放上去丢失之后的动作,其中type定义了请求的方法,url定义了当事件发生后去哪里进行请求,根据代码我们可以看出来,请求是通向/jsp/user.do的,其中data的内容和data的格式都给了出来。那么这个data是从哪里传出来的呢
请看下面的servlet
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);
}
}
public void pwdModify(HttpServletRequest req, HttpServletResponse resp){
//从session里取ID
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword = req.getParameter("oldpassword");
//万能map:结果集
Map<String, String> reslultMap = new HashMap<String, String>();
//如果session失效了
if (o==null){
reslultMap.put("result","sessionerror");
//输入的密码为空
}else if (StringUtils.isNullOrEmpty(oldpassword)){
reslultMap.put("result","error");
}else {
//session中用户的密码
String userPassword = ((User) o).getUserPassword();
if (oldpassword.equals(userPassword)){
reslultMap.put("result","true");
}else {
reslultMap.put("result","false");
}
}
try {
resp.setContentType("application/json");
PrintWriter writer = resp.getWriter();
writer.write(JSONArray.toJSONString(reslultMap));
writer.flush();//刷新关闭
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
这是userservlet中根据前段id写的方法,这里的doGet会根据data中对method的参数进行选择方法(data中的参数都给到了request),得到了pwdModify方法名字后进入方法,在session里得到用户对象,在data里得到的旧密码,并在下面进行判断,共以下几种情况:
- session失效了
- session没失效
- 输入的旧密码为空
- 输入的旧密码不为空
- 密码与session用户里密码不相等
- 密码与session用户里密码相等
我们新建一个map,map中是键值对:result与对应的值
在最下面的这种情况中,我们新建一个resp输出流,将这个map变成json输出去,map就到了js里,我们根据map的值做出不同的应对
5.用户管理实现
- 导入分页的工具类
- 用户列表页面导入
- 用户列表
- 分页条
1、获取用户数量
- UserDao
//查询用户总数 public int getUserCount(Connection connection,String userName,int userRole) throws SQLException;
传入的参数,除了connection之外还要传入的东西,包括要查询的用户名String和权限int,在sql里查询数据总数要用count(1),因为count(*)会查询所有的数据列,十分缓慢,
-
UserDaoImpl
public int getUserCount(Connection connection, String userName, int userRole) throws SQLException { PreparedStatement pstm = null; ResultSet rs = null; Object[] params; ArrayList<Object> list = new ArrayList<>();//利用list来传递参数 int count = 0; if (connection != null) { StringBuffer sql = new StringBuffer();//利用StringBuffer和if来进行不同sql语句执行 sql.append("select count(1) as count from smbms_user u, smbms_role r where u.userRole = r.id"); if (!StringUtils.isNullOrEmpty(userName)) { sql.append(" and u.userName like ?"); list.add(userName);//index 0 } if (userRole > 0) { sql.append(" and r.id = ?"); list.add(userRole);//index 1 } //把list转为数组,变为参数 params = list.toArray(); //执行Basedao的查询功能返回结果集 rs = BaseDao.execute(connection, rs, pstm, sql.toString(), params); //将结果集中Count的值赋给count if (rs.next()) { count = rs.getInt("count"); } BaseDao.closeResource(null, pstm, rs); } return count; }
首先还是初始化参数,包括预指令,结果集,参数数组这些最基本的
在这个方法李我们首先还是老样子判断连接是否存在,但是在接下来有些许不同,注意,这里用了StringBuffer来进行不同的sql语句执行,append方法在查询全部成员的基础上用if来对不同的情况进行判断,添加不同的sql语句(注意空格)
同时用了list来进行参数的传递,逻辑如下:首先如果用户名或者用户权限的if判断成功,说明两个参数内部是有值的,将这个值放进列表中,同时sql语句也添加了一个?,这样在Basedao里的execute函数就可以进行执行了
-
UserService
//根据用户名或者角色查询用户总数 public int getUserCount(String userName,int userRole);
- UserSerivceImpl
//根据用户名或者角色查询用户总数 @Override public int getUserCount(String userName, int userRole) { Connection connection = null; int count = 0; try { connection = BaseDao.getConnection(); count= userDao.getUserCount(connection, userName, userRole); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } return count; }
服务层的实现就非常简单了,还是进行连接,,然后调取执行方法就可以
2、获取用户列表
- UserDao
//获取用户列表 public List<User> getUserList(Connection connection,String userName,int userRole,int currentPageNo, int pageSize) throws SQLException;
这里跟获取用户数对比多了两个参数,一个是当前页面号,一个是页面显示数量
-
UserDaoImpl
@Override public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws SQLException { PreparedStatement pstm = null; ResultSet rs = null; Object[] params; ArrayList<Object> list = new ArrayList<>();//利用list来传递参数 int currentPageSize = 0; ArrayList<User> users = 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"); if (!StringUtils.isNullOrEmpty(userName)) { sql.append(" and u.userName like ?"); list.add(userName);//index 0 } if (userRole > 0) { sql.append(" and r.id = ?"); list.add(userRole);//index 1 } sql.append(" order by creationDate DESC limit ?,?");//为sql添加分页和排序 currentPageSize = (currentPageNo - 1) * pageSize;//当前页面数等于d list.add(currentPageSize); list.add(pageSize); params = list.toArray(); rs = BaseDao.execute(connection, rs, pstm, 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")); users.add(user); } BaseDao.closeResource(null,pstm,rs); } return users; }
几乎是与获取用户数量是相同的,除了
sql.append(" order by creationDate DESC limit ?,?");//为sql添加分页和排序 currentPageSize = (currentPageNo - 1) * pageSize;//当前页面数等于(当前页面号-1)×页面尺寸 list.add(currentPageSize);//添加当前页面数 list.add(pageSize);//添加页面尺寸
这里涉及到数据库的limit指令,其中第一个currentPageSize是当前页数,第二个pageSize是告诉数据库每页显示的数据多少
-
UserService
//获取用户列表 public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) ;
- UserSerivceImpl
//获取用户列表 @Override public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) { Connection connection = null; List<User> userList = null; try { connection = BaseDao.getConnection(); userList= userDao.getUserList(connection, userName, userRole, currentPageNo, pageSize); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } return userList; }
3、角色管理实现
衍生问题:BaseDao有一部分用静态块做初始化,而服务层实现里都是用构造函数初始化,两者有何区别,后者与直接赋值又有何区别?
构造函数:执行时间比构造代码块时间晚,也是在对象初始化的时候运行。没有返回值,构造函数名称和类名一致。
构造代码块:执行时间比静态代码块晚,比构造函数早,和构造函数一样,只在对象初始化的时候运行。没有名字、参数和返回值。
静态代码块:最早执行,类被载入内存时执行,只执行一次。没有名字、参数和返回值,有关键字static。
静态代码块只会在类被载入内存时加载一次,是最先执行的,然后是构造代码块,最后才是构造函数。
构造代码块和构造函数都是在对象创建的时候执行,有几个对象就会执行几次。
因为BaseDao里的代码每次执行都会使用,有很大的重复性,所以放在静态代码块里,在内存中生成一次就结束了,减少调用次数,而服务层实现里调用的不是那么频繁,所以放在构造函数里。
构造函数与直接赋值是有区别的,在一个类没有实例化的时候,前者不会给变量赋值,节省内存
获取角色列表
对应职责,每一种操作对应一个包,比如对角色的操作就放在角色的包里
- RoleDao
//获取角色列表 public List<Role> getRoleList(Connection connection)throws SQLException;
参数只需要连接就可以了
-
RoleDaoImpl
//获取角色列表 @Override public List<Role> getRoleList(Connection connection) throws SQLException { PreparedStatement pstm = null; ResultSet rs = null; Object[] params ={}; ArrayList<Object> list = new ArrayList<>();//利用list来传递参数 ArrayList<Role> roles = new ArrayList<>(); if(connection!=null){ String sql ="Select * from smbms_role"; rs = BaseDao.execute(connection, rs, pstm, sql, params); while (rs.next()){ Role role = new Role(); role.setId(rs.getInt("id")); role.setRoleName(rs.getString("roleName")); role.setRoleCode(rs.getString("roleCode")); roles.add(role); } BaseDao.closeResource(null,pstm,rs); } return roles; }
- RoleService
//获取用户列表 public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) ;
- RoleServiceImpl
//获取用户列表 @Override public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) { Connection connection = null; List<User> userList = null; try { connection = BaseDao.getConnection(); userList= userDao.getUserList(connection, userName, userRole, currentPageNo, pageSize); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } return userList; }
4、servlet具体实现
- 获取前端的信息,并初始化参数
String queryUserName = req.getParameter("queryname");//前端输入的查询名字 String temp = req.getParameter("queryUserRole");//前端选择的用户权限 String pageIndex = req.getParameter("pageIndex");//当前页号 int queryUserRole = 0;//默认的用户权限为0 int userCount = 0;//默认的查询出来的用户总数 List<Role> roleList = null;//权限列表 List<User> userList = null;//用户列表 RoleService roleService = new RoleServiceImpl(); UserService userService = new UserServiceImpl(); //两个服务层 int paseSize = 5;//设置页面容量 int currentPageNo = 1;//设置当前页面 int totalCount = 0;//总记录数————用户数量 int totalPageCount = 0; //总页数————用户数量除以页面容量+1;
在这一步,先要明确接下来都有哪些初始化参数
-
判断前端信息是否正确
if (queryUserName == null) { queryUserName = ""; } if (temp != null && !temp.equals("")) { queryUserRole = Integer.parseInt(temp); } /* 1.currentPageNo 当前页号 2.pageIndex 当前页号 3.totalCount 记录总条数 4.totalPageCount 总页数 5.pageSize 页面容量 */ if (pageIndex != null) { currentPageNo = Integer.parseInt(pageIndex); }
分别对前端获得信息进行非空判断来保证安全性
-
获取具体的列表(调用业务层)
//获取用户列表 userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, paseSize); //获取用户总数 userCount = userService.getUserCount(queryUserName,queryUserRole); //获取角色列表 roleList = roleService.getRoleList();
通过调取业务层对一开始的参数进行赋值
-
开始进行分页工作
- 先初始化分页工具类
-
设置好参数
-
为变量赋值
-
控制首尾页
PageSupport pageSupport = new PageSupport(); pageSupport.setCurrentPageNo(currentPageNo); pageSupport.setPageSize(paseSize); pageSupport.setTotalCount(userCount); pageSupport.setTotalPageCount(); totalCount = pageSupport.getTotalCount(); totalPageCount = pageSupport.getTotalPageCount(); //控制首页和尾页 if(currentPageNo < 1){ currentPageNo = 1; }else if(currentPageNo > totalPageCount){ currentPageNo = totalPageCount; }
新建分页工具类,得到总记录数,总页数等信息,然后通过if来限制页数的加减
-
向前端传递值
req.setAttribute("roleList",roleList); req.setAttribute("userList",userList); 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);
衍生问题:前端页面下拉框数据回显问题
看前端代码的时候有一块代码我不是很明白
<select name="queryUserRole">
<c:if test="{roleList != null }">
<option value="0">--请选择--</option>
<c:forEach var="role" items="{roleList}">
<option
<c:if test="美元符号{role.id == queryUserRole}">selected="selected"</c:if>
value="{role.id}">{role.roleName}</option>
</c:forEach>
</c:if>
</select>
这里是权限选择下拉框的地方,其中在option标签里做了一个role.id queryUserRole的判断,我一直没整明白是干啥的。
在搜索引擎的帮助下,我似乎了解了,在选择好权限后显示的页面如果有分页,在点击下一页后就会改变。
因为虽然你在这一页李对权限进行了选择,但是进入下一页的时候权限又回到了默认状态,相当于查看的是全体权限。
因此需要进行判断并进行数据回显。
6.用户增删改查
1、增加
先看jsp页面,在userlist里有增加按钮的jsp页面(useradd.jsp),jsp页面提交了一个表单,那么就可以从dao层开始先写增加了。
套路还是一样的,
dao层
//增加用户
@Override
public int addUser(Connection connection,User user) throws Exception {
PreparedStatement preparedStatement = null;
String sql = "insert into smbms_user (userCode,userName,userPassword," +
"userRole,gender,birthday,phone,address,creationDate,createdBy) " +
"values(?,?,?,?,?,?,?,?,?,?)";
Object params[] = {user.getUserCode(),user.getUserName(),user.getUserPassword(),user.getUserRole(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getCreationDate(),user.getCreatedBy()};
int execute = 0;
if (connection != null) {
execute = BaseDao.execute(connection, preparedStatement, sql, params);
}
BaseDao.closeResource(null, preparedStatement, null);
return execute;
}
业务层
//增加用户
@Override
public boolean addUser(User user) {
Connection connection = null;
boolean flag = false;
try {
connection = BaseDao.getConnection();
connection.setAutoCommit(false);
int updateRows = userDao.addUser(connection, user);
connection.commit();
if (updateRows>0){
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
BaseDao.closeResource(connection,null,null);
}
return flag;
}
Servlet
在servletl里遇到了两个问题,首先是角色权限的jsp页面并没有像狂神那样直接出现下拉表单,jsp页面里也并没有出现select的option,我想了半天终于在js页面里找到了,原来是有一个ajax代码(前端真的不太行,之后要好好看看,mvc阶段必须顺带着看熟练了,不会写也得会看吧),ajax代码需求了一个servlet方法,不多说给他吧,用的业务层还是请求权限列表那个,ajax方面的参数是要求json返回,那我们就用map加fastJson包的方法和response流给他返回去。
遇到的第二个问题,填写完信息后没法提交,来吧,看看这个提交按钮的事件,果然还是js代码,对于按钮会验证前面几个东西是否填写的正确,都正确了啊,定睛一看原来是用户名根本就没有验证。还是要servlet代码!淦
原来这个js事件是要求去数据库里查询是否有这个用户名,天,难道还要从dao从头写一个出来?其实不用,在登录验证的时候我们写了得到登录用户的dao这里可以直接用。
首先判断,这个输入的用户名是否为空,如果为空直接给他报错,如果不为空悠悠两种情况
- 根据得到的登录用户为空
- 根据得到的鞥路用户不为空
第一种说明这个用户不存在
第二种说明这个用户在数据库里是有的
怎么返回给js信息我就不用多说了吧,上面角色权限都说了,map一套返回去,大功告成
2、删除
依旧是js触发事件,需要servlet的deluser方法,还是从dao开始,首先需要要从前端得到要删除的用户的id,根据id删除数据库内容,再根据返回的json消息进行相应的提示。
3、修改
这个修改分为两个步骤,首先,在页面点击修改按钮,会有一个跳转到修改的界面,这里是直接调用了查看页面写的getuserById的方法,直接通过ID得到一个User,放入req里,跳转到modify界面,并显示出来,接下来就要在js进行判断输入的正确性,让偶点击保存按钮,这时汇集提交到servlet里,同时隐藏域里写着方法名字,对应方法以及得到的数据,调取对应的业务层modify方法,进行修改操作。
4、查看
对比修改来可简单太多了,只需要在数据库通过id拿到User,返回给前端就可以了
Comments | NOTHING