【SSM】Spring+SpringMVC+MyBatis整合之学生管理系统
刚刚学习完SSM整合 就想着自己写一个学生管理系统…
一.搭建环境
1.创建数据库和创建表
做学生管理系统 肯定是需要2张表的
第一就是User表 用来管理用户名和密码
第二就是Student表 用来存储学生的信息
2.SSM环境搭建
创建一个Maven的web项目之后
首先导入我们之前自己整合的一些文件(这里我博客都有写,这里就不一一列举了)
pom.xml坐标文件,
applicationContext.xml配置文件,
jdbc.properties文件,
log4j.properties文件,
spring-mvc.xml配置文件,
web.xml配置文件(我经常忘记配这个文件 所以经常404~~)
创建我们的三层架构
引入我们前端的页面
创建测试类代码(主要做一些测试)
二,项目流程分析
点击Tomcat运行>>index.jsp
首页可以>>查询所有学生信息
我这边写了一个过滤器 如果没有登陆的话会让我们去登陆
当然如果你是第一次访问的话还没有账号可以去注册>>点击还没账号?去注册
我这边注册页面就写的比较简单 只有用户名和密码
当然如果你向后台提交空的用户名和密码还是会有相应的错误提示
记得在过滤器中一定要放行我们的登陆方法和注册方法
不然就会一直让你登陆 不会出现错误页面
点击>>重新注册返回注册界面>>注册成功>>跳转到登陆界面
输入正确的账号密码和验证码>>跳转到首页
这边红框中的两个功能我在后台是有逻辑判断的.但自动登陆的过滤器我这边就没有写
后期会补上~
这时候已经是登陆状态了>>查询所有学生信息
添加学生功能
这边重置和返回功能我这边还没写 后期完善会补上~
修改学生功能
修改学生这边会回显数据 所以在修改学生之前 我们实际上先要获取要修改的学生id
通过id去后台找到这个学生 再将找到的学生对象存到域对象中 获取回显数据
然后修改信息再提交到后台
删除学生功能
为了防止用户误操作 删除信息之前给出相应的提示
当用户点击确定 再去操作删除功能
点击取消 则返回界面
同理删除选中按钮功能也会给出相应的提示
接下来就是这个项目我个人认为比较复杂的功能
多条件查询和分页功能
思考一下,由于用户需要查询的条件不同的话,那么向我们后台传递的条件也可能是不同的
所以我们访问数据库时需要查询的sql语句也是不同的.
这个时候就需要用到Mybatis的动态sql
常见的Mybatis的动态sql写法是XML文件配置
我这个项目在Dao层都是用注解来开发的
那么注解是如何实现动态sql的呢?
我个人也在网上找了一些资料
然后向同学也取了取经,给出一种比较简单的用法.
在Dao层创建一个Provider的包 创建一个StudentDaoProvider 类
package com.itheima.dao.Provider; import com.itheima.domain.Student; public class StudentDaoProvider { public String findStudentByPage(Student student) { String name = student.getName(); String sex = student.getSex(); String address = student.getAddress(); String sql = "select * from student where 1 = 1"; if(name!=null&&!"null".equalsIgnoreCase(name)&&!"".equals(name)){ sql += " and name like '%"+name+"%' "; } if(sex!=null&&!"null".equalsIgnoreCase(sex)&&!"".equals(sex)){ sql += " and sex = '"+sex+"' "; } if(address!=null&&!"null".equalsIgnoreCase(address)&&!"".equals(address)){ sql += " and address = '"+address+"' "; } return sql; } }
这个类会返回一个sql语句 它会根据你从后台传来是Student对象取里面的属性值判断有没有内容
如果有内容就会给你判断 然后拼接你的sql
Dao层用到的是@SelectProvider注解
里面的参数是类型 加载类的字节码文件
方法 你要调用的是类中的哪个方法
也就相当于将类中返回的sql返回到这里执行查询条件了!
@SelectProvider(type = StudentDaoProvider.class,method = "findStudentByPage") List<Student> findStudentByPage(Student student);
我们来看一下日志效果
比如我们就查询两个条件
查询
红框中就是动态生成的sql 可以看到是两个参数并且会自动给我们带上分页的语句
返回的对象是一个
接下来说一下分页功能
在JavaWeb阶段我们在做分页功能的时候其实是非常的繁琐的 需要很多参数
比如当前页 开始页码 每页要展示的条数 总页数 总条数
有时候还需要计算一些值
在Mybatis框架中就很好的为我们解决了这个问题
所以这可能就是Mybatis框架带来的魅力吧!
直接先上代码
配置分页插件
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"> <!--配置数据源--> <property name="dataSource" ref="dataSource"/> <!--给实体类起别名--> <property name="typeAliasesPackage" value="com.itheima.domain"/> <!--配置分页插件--> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value>dialect=mysql</value> </property> </bean> </array> </property> </bean>
在查询语句前调用方法(传入当前页+每页显示的条数)两个参数
//设置分页相关参数 当前页+每页显示的条数 PageHelper.startPage(pageNums,pageSizes); List<Student> studentList = studentService.findStudentByPage(student); //将查询条件存到request共享域中 request.setAttribute("student",student); //获得与分页相关参数 PageInfo<Student> pageInfo = new PageInfo<Student>(studentList);
将返回的List集合封装到PageInfo这个类中
这个类很强大包括刚才提到的要计算的属性 这个类都统统给你计算好了
你只需要把这个list集合set进去 然后返回这个类给前端就可以了
可以看一下效果
我为什么要把Student也放到共享域中呢? 其实是为了在查询条件出来结果的时候
能把查询条件也回显给用户
前台又是如何展示这个数据的呢?
<c:forEach items="${pageInfo.list}" var="student" varStatus="s"> <tr> <td><input type="checkbox" name="uid" value="${student.id}"></td> <td>${student.id}</td> <td>${student.name}</td> <td>${student.age}</td> <td>${student.sex}</td> <td>${student.date}</td> <td>${student.email}</td> <td>${student.address}</td> <td> <a class="btn btn-default btn-sm" href="${pageContext.request.contextPath}/findStudentById?id=${student.id}">修改</a> <a class="btn btn-default btn-sm" href="javascript:deleteStudentById(${student.id});">删除</a></td> </td> </tr> </c:forEach>
分页条
<div style="text-align: center;"> <nav aria-label="Page navigation"> <ul class="pagination"> <%--上一页--%> <c:if test="${pageInfo.pageNum == 1}"> <li class="disabled"> </c:if> <c:if test="${pageInfo.pageNum != 1}"> <li> </c:if> <a href="${pageContext.request.contextPath}/findStudentByPage?pageNum=${pageInfo.pageNum - 1}&pageSize=5&name=${student.name}&sex=${student.sex}&address=${student.address}"aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <%--页码 判断页码状态--%> <c:forEach begin="1" end="${pageInfo.pages}" var="i" > <c:if test="${pageInfo.pageNum == i}"> <li class="active"><a href="${pageContext.request.contextPath}/findStudentByPage?pageNum=${i}&pageSize=5&name=${student.name}&sex=${student.sex}&address=${student.address}">${i}</a></li> </c:if> <c:if test="${pageInfo.pageNum != i}"> <li><a href="${pageContext.request.contextPath}/findStudentByPage?pageNum=${i}&pageSize=5&name=${student.name}&sex=${student.sex}&address=${student.address}">${i}</a></li> </c:if> </c:forEach> <%--下一页 判断页码状态--%> <c:if test="${pageInfo.pageNum >= pageInfo.pages}"> <li class="disabled"> </c:if> <c:if test="${pageInfo.pageNum < pageInfo.pages}"> <li> </c:if> <a href="${pageContext.request.contextPath}/findStudentByPage?pages=${pageInfo.pages}&pageNum=${pageInfo.pageNum + 1}&pageSize=5&name=${student.name}&sex=${student.sex}&address=${student.address}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> <br> <br> <%--显示记录和总页码--%> <span style="font-size: 17px;color: red;"> 共${pageInfo.total}条记录,共${pageInfo.pages}页 </span> </ul> </nav> </div>
分析
判断我们当前页码是否等于当前页码 如果等于就给当前页码一个
class="active"属性
当前页是深蓝色按钮~
判断当前页码是否小于等于1 如果小于等于1 就将上一页按钮禁用
判断当前页码是否大于等于总页数 如果大于等于总页数 就将下一页按钮禁用
尽管我们在前台对上一页和下一页进行了禁用
但当我们点击时它还会访问我们的方法
所以就会产生下一页没有数据的情况
所以我们需要在后台代码也进行判断
但是我们在分页之前又拿不到总页数的值 所以针对这个问题我就思考了一下
我们从前端可以传一个总页数的值在地址栏
可以看到我们总页数是2
下一页页码成了3
我们要的效果应该是
当我们当前页码大于总页数 就把总页数的值赋给当前页面
也就是说 if3>2 就2=2
因为我们下一页是需要将当前页面+1的
为了在index.jsp不出现查询语句的错误
写了一段我自己也非常嫌弃的判断
int pagess; if (pageNum==null||"".equals(pageNum)){ pageNum="1"; } if (pages==null||"".equals(pages)){ int pageNums = Integer.parseInt(pageNum); pagess = pageNums+1; }else{ pagess = Integer.parseInt(pages); } if (pageSize==null||"".equals(pageSize)){ pageSize="5"; } int pageNums = Integer.parseInt(pageNum); if (pageNums<=0){ pageNums=1; } int pageSizes = Integer.parseInt(pageSize); if (pageNums>pagess){ pageNums = pagess; }
我这个分页条就没有测试很多页会自动伸缩的功能 所以后期可能还会改进~
controller>>StudentController
package com.itheima.controller; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.itheima.domain.Student; import com.itheima.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.util.List; @Controller public class StudentController { @Autowired private StudentService studentService; /** * 查找学生 条件查询 * */ @RequestMapping("/findStudentByPage") public ModelAndView findStudentByPage(HttpServletRequest request,ModelAndView modelAndView,String pageNum,String pageSize,String pages,Student student/*String name,String sex ,String address*/){ int pagess; if (pageNum==null||"".equals(pageNum)){ pageNum="1"; } if (pages==null||"".equals(pages)){ int pageNums = Integer.parseInt(pageNum); pagess = pageNums+1; }else{ pagess = Integer.parseInt(pages); } if (pageSize==null||"".equals(pageSize)){ pageSize="5"; } int pageNums = Integer.parseInt(pageNum); if (pageNums<=0){ pageNums=1; } int pageSizes = Integer.parseInt(pageSize); if (pageNums>pagess){ pageNums = pagess; }//设置分页相关参数 当前页+每页显示的条数 PageHelper.startPage(pageNums,pageSizes); List<Student> studentList = studentService.findStudentByPage(student); //将查询条件存到request共享域中 request.setAttribute("student",student); //获得与分页相关参数 PageInfo<Student> pageInfo = new PageInfo<Student>(studentList);modelAndView.addObject("pageInfo",pageInfo); modelAndView.setViewName("/list.jsp"); return modelAndView; } /** * 添加学生 * */ @RequestMapping("/addStudent") public String addStudent(Student student){ studentService.addStudent(student); return "redirect:/findStudentByPage"; } /** *查找学生 * */ @RequestMapping("/findStudentById") public String findStudentById(int id,HttpServletRequest request) { Student student = studentService.findStudentById(id); request.setAttribute("student",student); return "forward:/update.jsp"; } /** * 修改学生 * */ @RequestMapping("/updateStudent") public String updateStudent(Student student){ studentService.updateStudent(student); return "redirect:/findStudentByPage"; } /** * 删除学生 * */ @RequestMapping("/deleteStudentById") public String deleteStudentById(int id){ studentService.deleteStudentById(id); return "redirect:/findStudentByPage"; } /** * 删除选中学生 * */ @RequestMapping("/deleteSelectedStudent") public String deleteSelectedStudent(int[] uid){ studentService.deleteSelectedStudent(uid); return "redirect:/findStudentByPage"; } }
controller>>UserController
package com.itheima.controller; import com.itheima.domain.User; import com.itheima.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.imageio.ImageIO; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; /** * 登陆 * */ @RequestMapping("/login") public ModelAndView login(User user,String checkCode,HttpServletRequest request,HttpServletResponse response) { ModelAndView modelAndView = new ModelAndView(); HttpSession session = request.getSession(); String checkCode_session = (String) session.getAttribute("checkCode_session"); session.removeAttribute("checkCode_session"); //判断验证码 if (checkCode_session != null && checkCode_session.equalsIgnoreCase(checkCode)) { User user1 = userService.findUsernameAndPassword(user); if (user1 == null) { modelAndView.addObject("login_error", "用户名密码错误"); modelAndView.setViewName("/login.jsp"); return modelAndView; } else { //登录成功 获取用户是否勾选了保存用户名 String check_user = request.getParameter("check_user"); //获取用户是否勾选了自动登陆 String check_auto = request.getParameter("check_auto"); if ("true".equalsIgnoreCase(check_user)) { //说明用户勾选了记住用户名 //将用户名保存到Cookie中 Cookie cookie_uu = new Cookie("uu_name", user1.getUsername()); cookie_uu.setMaxAge(60 * 60 * 24 * 7); cookie_uu.setPath(request.getContextPath()); response.addCookie(cookie_uu); } if ("true".equalsIgnoreCase(check_auto)){ //说明用户勾选了自动登陆 //将用户名和密码保存到Cookie Cookie cookie_auto = new Cookie("auto_login", user1.getUsername() + "#" + user1.getPassword()); cookie_auto.setMaxAge(60*60*24*7); cookie_auto.setPath(request.getContextPath()); response.addCookie(cookie_auto); } //将用户信息存入session session.setAttribute("user1",user1); modelAndView.setViewName("/index.jsp"); return modelAndView; } }else { session.setAttribute("cc_error","验证码错误"); modelAndView.setViewName("redirect:/login.jsp"); return modelAndView; } } /** * 注册 * */ @RequestMapping("/register") public ModelAndView register(ModelAndView modelAndView,String username, String password){ if (username==null||username.equals("")&&password==null||password.equals("")){ //如果用户名为空 返回错误消息 modelAndView.addObject("error","用户名或密码为空"); modelAndView.setViewName("forward:/error.jsp"); return modelAndView; } us 4000 erService.registerUser(username,password); modelAndView.setViewName("forward:/login.jsp"); return modelAndView; } /** * 验证码 * */ @RequestMapping("/checkCode") public void CheckCode(HttpServletRequest request, HttpServletResponse response) throws IOException { //服务器通知浏览器不要缓存 response.setHeader("pragma","no-cache"); response.setHeader("cache-control","no-cache"); response.setHeader("expires","0"); //在内存中创建一个长100,宽40的图片,默认黑色背景 //参数一:长 //参数二:宽 //参数三:颜色 int width = 100; int height = 40; BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //获取画笔 Graphics g = image.getGraphics(); //设置画笔颜色为灰色 g.setColor(Color.GRAY); //填充图片 g.fillRect(0,0, width,height); //产生4个随机验证码,12Ey String checkCode_session = getCheckCode(); //将验证码放入HttpSession中 request.getSession().setAttribute("checkCode_session",checkCode_session); //设置画笔颜色为黄色 g.setColor(Color.YELLOW); //设置字体的小大 g.setFont(new Font("黑体", Font.BOLD,26)); //向图片上写入验证码 g.drawString(checkCode_session,25,30); //将内存中的图片输出到浏览器 //参数一:图片对象 //参数二:图片的格式,如PNG,JPG,GIF //参数三:图片输出到哪里去 ImageIO.write(image,"PNG",response.getOutputStream()); } /** * 产生4位随机字符串 */ private String getCheckCode() { String base = "0123456789ABCDEFGabcdefg"; int size = base.length(); Random r = new Random(); StringBuffer sb = new StringBuffer(); for(int i=1;i<=4;i++){ //产生0到size-1的随机值 int index = r.nextInt(size); //在base字符串中获取下标为index的字符 char c = base.charAt(index); //将c放入到StringBuffer中去 sb.append(c); } return sb.toString(); } }
dao>>StudentDao
package com.itheima.dao; import com.itheima.dao.Provider.StudentDaoProvider; import com.itheima.domain.Student; import org.apache.ibatis.annotations.*; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface StudentDao { @Select("select * from student") List<Student> findAllStudent(); @Insert("insert into student Values(null,#{name},#{age},#{sex},#{date},#{email},#{address})") Integer addStudent(Student student); @Select("select * from student where id = #{id}") Student findStudentById(int id); @Update("update student set name=#{name},age=#{age},sex=#{sex},date=#{date},email=#{email},address=#{address}where id=#{id}") void updateStudent(Student student); @Delete("delete from student where id = #{id}") void deleteStudentById(int id); @SelectProvider(type = StudentDaoProvider.class,method = "findStudentByPage") List<Student> findStudentByPage(Student student);}
dao>>UserDao
package com.itheima.dao; import com.itheima.domain.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; @Repository public interface UserDao { @Insert("insert into user values(null,#{username},#{password})") public void registerUser(@Param("username")String username, @Param("password")String password); @Select("select * from user where username = #{username} and password = #{password}") User findUsernameAndPassword(User user); }
domain实体类(忽略)
interceptor>>过滤器
package com.itheima.interceptor; import com.itheima.domain.User; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class PrivilegeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { HttpSession session = request.getSession(); User user = (User) session.getAttribute("user1"); if (user==null){ //没有登陆 response.sendRedirect(request.getContextPath()+"/login.jsp"); return false; } return true; } }
service>>impl>>StudentServiceImpl
package com.itheima.service.impl; import com.itheima.dao.StudentDao; import com.itheima.domain.Student; import com.itheima.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @Transactional public class StudentServiceImpl implements StudentService { @Autowired private StudentDao studentDao; @Override public List<Student> findAllStudent() { return studentDao.findAllStudent(); } @Override public void addStudent(Student student) { studentDao.addStudent(student); } @Override public Student findStudentById(int id) { return studentDao.findStudentById(id); } @Override public void updateStudent(Student student) { studentDao.updateStudent(student); } @Override public void deleteStudentById(int id) { studentDao.deleteStudentById(id); } @Override public void deleteSelectedStudent(int[] uid) { for (int id : uid) { studentDao.deleteStudentById(id); } } @Override public List<Student> findStudentByPage(Student student) { return studentDao.findStudentByPage(student); } }
user>>impl>>UserServiceImpl
package com.itheima.service.impl; import com.itheima.dao.UserDao; import com.itheima.domain.User; import com.itheima.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void registerUser(String username, String password) { userDao.registerUser(username,password); } @Override public User findUsernameAndPassword(User user) { return userDao.findUsernameAndPassword(user); } }
三.项目总结
整个学生信息管理系统就这样写完了…其实不算是很复杂…
因为之前也写过Servlet版的…
所以在使用SSM整合的时候…
其实Dao层很多代码非常的简洁.都是框架帮我们完成…
之前我们每个功能都需要写一个Servlet…
SpringMVC的话只需要写方法就好了…
使用注解开发效率也会很高…
我已经将源码放到我的码云上面
码云地址:https://gitee.com/gubingkun/ssm_student_manage.git
以上内容自己整理 如有不正确的地方 欢迎批评指正~
Java笔记-坤坤
- SSM学生管理系统SpringMVC+MyBatis
- J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis+Lucene+Redis+MAVEN)(1)框架整合构建
- SuperMarketSys_SSM超市管理系统(Spring+SpringMVC+Mybatis)
- 框架整合构建 :SSM框架构建 系统(Spring+SpringMVC+MyBatis+Lucene+Redis+MAVEN)
- SuperMarketSys_SSM超市管理系统(Spring+SpringMVC+Mybatis)
- [spring+springmvc+mybatis实践]学生社团管理系统
- 【Spring+SpringMVC+Mybatis】利用SSM整合,完成用户登录、注册、修改密码系统
- SVN+Spring+SpringMVC+MyBatis+Mysql+Maven+Myeclipse整合开发实战:酒店管理系统
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- 【SSM】spring+springMVC+mybatis开发环境快速整合
- SSM系列1:简易详细的(Spring +Springmvc+Mybatis)框架整合搭建
- 一步一步完成SSM框架整合(Spring+Spring MVC + Mybatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM(spring+springmvc+mybatis)整合
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- 整合maven+spring+springmvc+mybatis实现ssm通用增删查改基础开发框架
- 使用Idea创建ssm项目,SpringMVC+Spring+MyBatis+Maven整合
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)