2019独角兽企业重金招聘Python工程师标准>>>

技术准备

为了完成这个项目,需要掌握如下技术:

  • Java
    基础知识
  • 前端:
    HTML, CSS, JAVASCRIPT, JQUERY
  • J2EE:
    Tomcat, Servlet, JSP, Filter
  • 框架:
    Spring, Spring MVC, MyBatis, Spring 与 MyBatis 整合, SSM 整合
  • 数据库:
    MySQL
  • 开发工具:
    IDEA, Maven

开发流程

之前虽然已经使用 Servlet + JSP 完成了简单的开发,这次使用 SSM 仅仅是重构工作,但我们仍然按照商业项目的开发步骤来一步一步完成,进一步熟悉这个过程,重复的部分我就直接复制了。

① 需求分析

首先要确定要做哪些功能

  • 使用数据库保存数据
  • 增删改查学生的信息(学号,名称,年龄,性别,出生日期)

② 表结构设计

根据需求,那么只需要一个 student 表就能够完成功能了。

  • 创建数据库:student
    将数据库编码格式设置为 UTF-8 ,便于存取中文数据

    DROP DATABASE IF EXISTS student;
    CREATE DATABASE student DEFAULT CHARACTER SET utf8;
  • 创建学生表:student
    不用学生学号(studentID)作为主键的原因是:不方便操作,例如在更新数据的时候,同时也要更改学号,那这样的操作怎么办呢?
    所以我们加了一个 id 用来唯一表示当前数据。

    CREATE TABLE student(id int(11) NOT NULL AUTO_INCREMENT,student_id int(11) NOT NULL UNIQUE,name varchar(255) NOT NULL,age int(11) NOT NULL,sex varchar(255) NOT NULL,birthday date DEFAULT NULL,PRIMARY KEY (id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

MySQL 在 Windows 下不区分大小写,但在 Linux 下默认区分大小写,因此,数据库名、表明、字段名都不允许出现任何大写字母,避免节外生枝。

③ 原型设计

就是设计界面,在商业项目中,这是很重要的一步,我们可以解除界面原型,低成本、高效率的与客户达成需求的一致性

这个项目一共就分为两个页面:

  • 主页面:

  • 学生编辑页面:

④ SSM 环境搭建

在真正开始编写代码之前,我们首先需要先来搭建好我们的 SSM 环境。

第一步:创建 Maven webapp 项目

首先新建工程,选择 Maven 标签,然后勾选上【Create from archetype】选择 webapp:

点击下一步,填写上【GroupId】和【ArtifactId】:

  • GroupId:项目组织唯一的标识符,实际对应 JAVA 的包的结构,也就是 main 目录下 java 的目录结构(包)
  • AritifactId:项目的唯一标识符,实际对应项目的名称,就是项目根目录的名称
  • 实际上你可以乱填上试试,我就不乱填了

然后是确认项目路径,这一步你可以看到 Maven 配置中的参数,不需要做改动,直接下一步就可以(图中的路径是我配置的本地 Maven 仓库的地址):

确认项目名称和路径,点击【Finish】即可:

等待一会儿,控制台就会有创建成功的提示信息,我们把【Enable Auto-Import】点上,这个提示会在每次 pom.xml 有改动时出现,自动导入,省掉麻烦:

第二步:搭建项目目录结构

下面就是 Maven 风格的 webapp 的默认目录结构:

  • 注意: webapp 是默认没有 java 源文件也没有 test 目录的。

遵循 Maven 的统一项目结构,我们搭建出项目的完整目录结构如下图:

  • 我们并没有使用 Log4j 来输出日志,而是使用 logback
  • 提示:我们可以在 IDEA 中右键目录然后选择【Make Directory as】,让 IDEA 识别不同的目录作用

这里的目录建好之后还需要设置一下,让 IDEA 识别目录作用,选择【File】>【Project Structure】:

设置好之后点击 OK,即完成了项目目录的搭建。

第三步:配置文件内容

在【pom.xml】文件中声明依赖的 jar 包 :

<?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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><packaging>war</packaging><name>StudentManagerSSM</name><groupId>cn.wmyskxz</groupId><artifactId>StudentManagerSSM</artifactId><version>1.0-SNAPSHOT</version><build><plugins><plugin><groupId>org.mortbay.jetty</groupId><artifactId>maven-jetty-plugin</artifactId><version>6.1.7</version><configuration><connectors><connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"><port>8888</port><maxIdleTime>30000</maxIdleTime></connector></connectors><webAppSourceDirectory>${project.build.directory}/${pom.artifactId}-${pom.version}</webAppSourceDirectory><contextPath>/</contextPath></configuration></plugin></plugins></build><properties><!-- 设置项目编码编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- spring版本号 --><spring.version>4.3.5.RELEASE</spring.version><!-- mybatis版本号 --><mybatis.version>3.4.1</mybatis.version></properties><dependencies><!-- jstl标签 --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.apache.taglibs</groupId><artifactId>taglibs-standard-impl</artifactId><version>1.2.5</version></dependency><!-- java ee --><dependency><groupId>javax</groupId><artifactId>javaee-api</artifactId><version>7.0</version></dependency><!-- 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- 实现slf4j接口并整合 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.2</version></dependency><!-- JSON --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.7</version></dependency><!-- 数据库 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.41</version><scope>runtime</scope></dependency><!-- 数据库连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!-- MyBatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- mybatis/spring整合包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency></dependencies></project>
  • <build> 标签是默认生成的
  • 我们在 <properties> 中声明了编码格式以及使用的 spring 和 mybatis 的版本号,然后在 <dependencies> 中声明了具体的 jar 包

在【web.xml】中声明编码过滤器并配置 DispatcherServlet :

<?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_3_1.xsd"version="3.1"><!-- 编码过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 配置DispatcherServlet --><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 配置springMVC需要加载的配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-*.xml</param-value></init-param><load-on-startup>1</load-on-startup><async-supported>true</async-supported></servlet><servlet-mapping><servlet-name>SpringMVC</servlet-name><!-- 匹配所有请求 --><url-pattern>/</url-pattern></servlet-mapping></web-app>

在【spring-mybatis.xml】中完成 spring 和 mybatis 的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 扫描service包下所有使用注解的类型 --><context:component-scan base-package="cn.wmyskxz.service"/><!-- 配置数据库相关参数properties的属性:${url} --><context:property-placeholder location="classpath:jdbc.properties"/><!-- 数据库连接池 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><property name="maxPoolSize" value="${c3p0.maxPoolSize}"/><property name="minPoolSize" value="${c3p0.minPoolSize}"/><property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/><property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/><property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/></bean><!-- 配置SqlSessionFactory对象 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入数据库连接池 --><property name="dataSource" ref="dataSource"/><!-- 扫描entity包 使用别名 --><property name="typeAliasesPackage" value="cn.wmyskxz.entity"/><!-- 扫描sql配置文件:mapper需要的xml文件 --><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 注入sqlSessionFactory --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/><!-- 给出需要扫描Dao接口包 --><property name="basePackage" value="cn.wmyskxz.dao"/></bean><!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 注入数据库连接池 --><property name="dataSource" ref="dataSource"/></bean><!-- 配置基于注解的声明式事务 --><tx:annotation-driven transaction-manager="transactionManager"/></beans>

在【spring-mvc.xml】中完成 Spring MVC 的相关配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><!-- 扫描web相关的bean --><context:component-scan base-package="cn.wmyskxz.controller"/><!-- 开启SpringMVC注解模式 --><mvc:annotation-driven/><!-- 静态资源默认servlet配置 --><mvc:default-servlet-handler/><!-- 配置jsp 显示ViewResolver --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean></beans>

在【jdbc.properties】中配置 c3p0 数据库连接池:

jdbc.driver=com.mysql.jdbc.Driver
#数据库地址
jdbc.url=jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8
#用户名
jdbc.username=root
#密码
jdbc.password=root
#最大连接数
c3p0.maxPoolSize=30
#最小连接数
c3p0.minPoolSize=10
#关闭连接后不自动commit
c3p0.autoCommitOnClose=false
#获取连接超时时间
c3p0.checkoutTimeout=10000
#当获取连接失败重试次数
c3p0.acquireRetryAttempts=2

在【logback.xml】中完成日志输出的相关配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="STDOUT"/></root>
</configuration>

以上就完成了 SSM 框架的基本配置:

  • 添加进了 SSM 项目所需要的 jar 包
  • 配置好了 spring/mybatis/spring MVC 的相关配置信息(自动扫描 cn.wmyskxz 包下的带有注解的类)
  • 通过 xml 配置的方式配置好了日志和数据库

⑤ 实体类设计

实体类仅仅是对数据库中表的一一映射(表中字段名应该和实体类中的名称一一对应),同时可能还需要兼顾对业务能力的支持。

  • 在 Packge【cn.wmyskxz.entity】下创建 Student 类:
package cn.wmyskxz.entity;import java.util.Date;/**
•Student 实体类*/public class Student {private int id;private int student_id;private String name;private int age;private String sex;private Date birthday;/* getter and setter */}

⑤ DAO 类的设计

DAO,即 Date Access Object,数据库访问对象,就是对数据库相关操作的封装,让其他地方看不到 JDBC 的代码。

在【cn.wmyskxz.dao】包下创建【StudentDao】接口:

package cn.wmyskxz.dao;import cn.wmyskxz.entity.Student;import java.util.List;public interface StudentDao {int getTotal();void addStudent(Student student);void deleteStudent(int id);void updateStudent(Student student);Student getStudent(int id);List<Student> list(int start, int count);
}

然后在【resources/mapper】下创建好对应的映射文件【StudengDao.xml】:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- 将namespace的值设置为DAO类对应的路径 -->
<mapper namespace="cn.wmyskxz.dao.StudentDao"><!-- 查询数据条目 --><select id="getTotal" resultType="int">SELECT COUNT(*) FROM student</select><!-- 增加一条数据 --><insert id="addStudent" parameterType="Student">INSERT INTO student VALUES(NULL, #{student_id}, #{name}, #{age}, #{sex}, #{birthday})</insert><!-- 删除一条数据 --><delete id="deleteStudent" parameterType="int">DELETE FROM student WHERE id = #{id}</delete><!-- 更新一条数据 --><update id="updateStudent" parameterType="Student">UPDATE student SET student_id = #{student_id}, name = #{name},age = #{age}, sex = #{sex}, birthday = #{birthday} WHERE id = #{id}</update><!-- 查询一条数据 --><select id="getStudent" resultMap="student" parameterType="int">SELECT * FROM student WHERE id = #{id}</select><resultMap id="student" type="student"><id column="id" property="id"/><result column="student_id" property="student_id"/><result column="name" property="name"/><result column="age" property="age"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/></resultMap><!-- 查询从start位置开始的count条数据--><select id="list" resultMap="student">SELECT * FROM student ORDER BY student_id desc limit #{param1}, #{param2}</select>
</mapper>

编写好了 Dao 类是需要测试的,这里测试类就不给出了。

⑦ 业务类设计

  • 问题: 为什么不直接使用 Dao 类而是还要在上面封装一层 Service 层呢?
  • 回答:
    基于责任分离的原则,Dao 层就应该专注于对数据库的操作,而在 Service 层我们可以增加一些非 CRUD 的方法去更好的完成本身抽离出来的 service 服务(业务处理)。

在【cn.wmyskxz.service】包下创建【StudentService】接口:

package cn.wmyskxz.service;import cn.wmyskxz.entity.Student;import java.util.List;public interface StudentService {/*** 获取到 Student 的总数* @return*/int getTotal();/*** 增加一条数据* @param student*/void addStudent(Student student);/*** 删除一条数据* @param id*/void deleteStudent(int id);/*** 更新一条数据* @param student*/void updateStudent(Student student);/*** 找到一条数据* @param id* @return*/Student getStudent(int id);/*** 列举出从 start 位置开始的 count 条数据* @param start* @param count* @return*/List<Student> list(int start, int count);
}

并在相同包名下创建实现类【StudentServiceImpl】:

package cn.wmyskxz.service;import cn.wmyskxz.dao.StudentDao;
import cn.wmyskxz.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** StudentService 的实现类** @author: @我没有三颗心脏* @create: 2018-04-23-下午 13:51*/
@Service
public class StudentServiceImpl implements StudentService {@AutowiredStudentDao studentDao;public int getTotal() {return studentDao.getTotal();}public void addStudent(Student student) {studentDao.addStudent(student);}public void deleteStudent(int id) {studentDao.deleteStudent(id);}public void updateStudent(Student student) {studentDao.updateStudent(student);}public Student getStudent(int id) {return studentDao.getStudent(id);}public List<Student> list(int start, int count) {return studentDao.list(start, count);}
}

⑧ 功能开发

在【cn.wmyskxz.controller】包下创建【StudentController】控制器,代码基本上都是复制黏贴之前在 Servlet 中的代码:

package cn.wmyskxz.controller;import cn.wmyskxz.entity.Student;
import cn.wmyskxz.service.StudentService;
import cn.wmyskxz.util.Page;
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 javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;/*** Student 控制器** @author: @我没有三颗心脏* @create: 2018-04-23-下午 13:27*/
@Controller
@RequestMapping("")
public class StudentController {@Autowiredprivate StudentService studentService;@RequestMapping("/addStudent")public String addStudent(HttpServletRequest request, HttpServletResponse response) {Student student = new Student();int studentID = Integer.parseInt(request.getParameter("student_id"));String name = request.getParameter("name");int age = Integer.parseInt(request.getParameter("age"));String sex = request.getParameter("sex");Date birthday = null;// String 类型按照 yyyy-MM-dd 的格式转换为 java.util.Date 类SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");try {birthday = simpleDateFormat.parse(request.getParameter("birthday"));} catch (ParseException e) {e.printStackTrace();}student.setStudent_id(studentID);student.setName(name);student.setAge(age);student.setSex(sex);student.setBirthday(birthday);studentService.addStudent(student);return "redirect:listStudent";}@RequestMapping("/listStudent")public String listStudent(HttpServletRequest request, HttpServletResponse response) {// 获取分页参数int start = 0;int count = 10;try {start = Integer.parseInt(request.getParameter("page.start"));count = Integer.parseInt(request.getParameter("page.count"));} catch (Exception e) {}Page page = new Page(start, count);List<Student> students = studentService.list(page.getStart(), page.getCount());int total = studentService.getTotal();page.setTotal(total);request.setAttribute("students", students);request.setAttribute("page", page);return "listStudent";}@RequestMapping("/deleteStudent")public String deleteStudent(int id) {studentService.deleteStudent(id);return "redirect:listStudent";}@RequestMapping("/editStudent")public ModelAndView editStudent(int id) {ModelAndView mav = new ModelAndView("editStudent");Student student = studentService.getStudent(id);mav.addObject("student", student);return mav;}@RequestMapping("/updateStudent")public String updateStudent(HttpServletRequest request, HttpServletResponse response) {Student student = new Student();int id = Integer.parseInt(request.getParameter("id"));int student_id = Integer.parseInt(request.getParameter("student_id"));String name = request.getParameter("name");int age = Integer.parseInt(request.getParameter("age"));String sex = request.getParameter("sex");SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date birthday = null;try {birthday = simpleDateFormat.parse(request.getParameter("birthday"));} catch (ParseException e) {e.printStackTrace();}student.setId(id);student.setStudent_id(student_id);student.setName(name);student.setAge(age);student.setSex(sex);student.setBirthday(birthday);studentService.updateStudent(student);return "redirect:listStudent";}
}
  • 注意: 所有的学号都用 student_id 表示,为了契合在数据库中的字段名(包括下面的 JSP 文件)

JSP 文件也直接黏之前的就好了,不过需要注意所有的 name 属性

  • 【listStudent.jsp】:
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><html>
<head><%-- 引入JQ和Bootstrap --%><script src="js/jquery/2.0.0/jquery.min.js"></script><link href="css/bootstrap/3.3.6/bootstrap.min.css" rel="stylesheet"><script src="js/bootstrap/3.3.6/bootstrap.min.js"></script><link href="css/style.css" rel="stylesheet"><title>学生管理页面 - 首页</title><script>$(function () {$("ul.pagination li.disabled a").click(function () {return false;});});</script>
</head><body><div class="listDIV"><table class="table table-striped table-bordered table-hover table-condensed"><caption>学生列表 - 共${page.total}人</caption><thead><tr class="success"><th>学号</th><th>姓名</th><th>年龄</th><th>性别</th><th>出生日期</th><th>编辑</th><th>删除</th></tr></thead><tbody><c:forEach items="${students}" var="s" varStatus="status"><tr><td>${s.student_id}</td><td>${s.name}</td><td>${s.age}</td><td>${s.sex}</td><td>${s.birthday}</td><td><a href="/editStudent?id=${s.id}"><span class="glyphicon glyphicon-edit"></span> </a></td><td><a href="/deleteStudent?id=${s.id}"><span class="glyphicon glyphicon-trash"></span> </a></td></tr></c:forEach></tbody></table>
</div><nav class="pageDIV"><ul class="pagination"><li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>><a href="?page.start=0"><span>«</span></a></li><li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>><a href="?page.start=${page.start-page.count}"><span>‹</span></a></li><c:forEach begin="0" end="${page.totalPage-1}" varStatus="status"><c:if test="${status.count*page.count-page.start<=30 && status.count*page.count-page.start>=-10}"><li <c:if test="${status.index*page.count==page.start}">class="disabled"</c:if>><ahref="?page.start=${status.index*page.count}"<c:if test="${status.index*page.count==page.start}">class="current"</c:if>>${status.count}</a></li></c:if></c:forEach><li <c:if test="${!page.hasNext}">class="disabled"</c:if>><a href="?page.start=${page.start+page.count}"><span>›</span></a></li><li <c:if test="${!page.hasNext}">class="disabled"</c:if>><a href="?page.start=${page.last}"><span>»</span></a></li></ul>
</nav><div class="addDIV"><div class="panel panel-success"><div class="panel-heading"><h3 class="panel-title">增加学生</h3></div><div class="panel-body"><form method="post" action="/addStudent" role="form"><table class="addTable"><tr><td>学号:</td><td><input type="text" name="student_id" id="student_id" placeholder="请在这里输入学号"></td></tr><tr><td>姓名:</td><td><input type="text" name="name" id="name" placeholder="请在这里输入名字"></td></tr><tr><td>年龄:</td><td><input type="text" name="age" id="age" placeholder="请在这里输入年龄"></td></tr><tr><td>性别:</td><td><input type="radio" class="radio radio-inline" name="sex" value="男"> 男<input type="radio" class="radio radio-inline" name="sex" value="女"> 女</td></tr><tr><td>出生日期:</td><td><input type="date" name="birthday" id="birthday" placeholder="请在这里输入出生日期"></td></tr><tr class="submitTR"><td colspan="2" align="center"><button type="submit" class="btn btn-success">提 交</button></td></tr></table></form></div></div></div></body>
</html>
  • 【editStudent.jsp】:
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html>
<head><%-- 引入JQ和Bootstrap --%><script src="js/jquery/2.0.0/jquery.min.js"></script><link href="css/bootstrap/3.3.6/bootstrap.min.css" rel="stylesheet"><script src="js/bootstrap/3.3.6/bootstrap.min.js"></script><link href="css/style.css" rel="stylesheet"><title>学生管理页面 - 编辑页面</title>
</head><body><div class="editDIV"><div class="panel panel-success"><div class="panel-heading"><h3 class="panel-title">编辑学生</h3></div><div class="panel-body"><form method="post" action="/updateStudent" role="form"><table class="editTable"><tr><td>学号:</td><td><input type="text" name="student_id" id="student_id" value="${student.student_id}"placeholder="请在这里输入学号"></td></tr><tr><td>姓名:</td><td><input type="text" name="name" id="name" value="${student.name}" placeholder="请在这里输入名字"></td></tr><tr><td>年龄:</td><td><input type="text" name="age" id="age" value="${student.age}" placeholder="请在这里输入年龄"></td></tr><tr><td>性别:</td><td><input type="radio" class="radio radio-inline" name="sex" value="男"> 男<input type="radio" class="radio radio-inline" name="sex" value="女"> 女</td></tr><tr><td>出生日期:</td><td><input type="date" name="birthday" id="birthday" value="${student.birthday}"placeholder="请在这里输入出生日期"></td></tr><tr class="submitTR"><td colspan="2" align="center"><input type="hidden" name="id" value="${student.id}"><button type="submit" class="btn btn-success">提 交</button></td></tr></table></form></div></div></div></body>
</html>
  • style.css 文件:
body {padding-top: 60px;
}div.listDIV {width: 600px;margin: 0 auto;
}div.editDIV {width: 400px;margin: 0 auto;
}nav.pageDIV {text-align: center;
}div.addDIV {width: 300px;margin: 0 auto;
}table.addTable {width: 100%;padding: 5px;
}table.addTable td {padding: 5px;
}table.editTable {width: 100%;padding: 5px;
}table.editTable td {padding: 5px;
}

项目的整体结构

分页功能

  • 首先在 Packge【util】包下创建一个 Page 工具类:
package cn.wmyskxz.util;public class Page {int start;      // 开始数据int count;      // 每一页的数量int total;      // 总共的数据量public Page(int start, int count) {super();this.start = start;this.count = count;}public boolean isHasPreviouse(){if(start==0)return false;return true;}public boolean isHasNext(){if(start==getLast())return false;return true;}public int getTotalPage(){int totalPage;// 假设总数是50,是能够被5整除的,那么就有10页if (0 == total % count)totalPage = total /count;// 假设总数是51,不能够被5整除的,那么就有11页elsetotalPage = total / count + 1;if(0==totalPage)totalPage = 1;return totalPage;}public int getLast(){int last;// 假设总数是50,是能够被5整除的,那么最后一页的开始就是40if (0 == total % count)last = total - count;// 假设总数是51,不能够被5整除的,那么最后一页的开始就是50elselast = total - total % count;last = last<0?0:last;return last;}// 各种 setter 和 getter
}
  • totalPage 是计算得来的数,用来表示页码一共的数量

在首页显示的 StudentList 用 page 的参数来获取:

List<Student> students = studentService.list(page.getStart(), page.getCount());

并且在映射文件中用 LIMIT 关键字:

<!-- 查询从start位置开始的count条数据-->
<select id="list" resultMap="student">SELECT * FROM student ORDER BY student_id desc limit #{param1}, #{param2}
</select>
  • 第一个参数为 start,第二个参数为 count
    这样就能根据分页的信息来获取到响应的数据

  • 编写分页栏:

1.写好头和尾

<nav class="pageDIV"><ul class="pagination">.....</ul>
</nav>

2.写好« 这两个功能按钮
使用 <c:if>标签来增加边界判断,如果没有前面的页码了则设置为disable状态

        <li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>><a href="?page.start=0"><span>«</span></a></li><li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>><a href="?page.start=${page.start-page.count}"><span>‹</span></a></li>

再通过 JavaScrip 代码来完成禁用功能:

<script>$(function () {$("ul.pagination li.disabled a").click(function () {return false;});});
</script>

3.完成中间页码的编写
0 循环到 page.totalPage - 1varStatus 相当于是循环变量

  • status.count 是从1开始遍历
  • status.index 是从0开始遍历
  • 要求:显示当前页码的前两个和后两个就可,例如当前页码为3的时候,就显示 1 2 3(当前页) 4 5 的页码
  • 理解测试条件:
    -10 <= 当前页*每一页显示的数目 - 当前页开始的数据编号 <= 30

  • 只要理解了这个判断条件,其他的就都好理解了
<c:forEach begin="0" end="${page.totalPage-1}" varStatus="status"><c:if test="${status.count*page.count-page.start<=30 && status.count*page.count-page.start>=-10}"><li <c:if test="${status.index*page.count==page.start}">class="disabled"</c:if>><ahref="?page.start=${status.index*page.count}"<c:if test="${status.index*page.count==page.start}">class="current"</c:if>>${status.count}</a></li></c:if>
</c:forEach>

4.在控制器中获取参数

// 获取分页参数
int start = 0;
int count = 10;try {start = Integer.parseInt(request.getParameter("page.start"));count = Integer.parseInt(request.getParameter("page.count"));
} catch (Exception e) {
}....// 共享 page 数据
request.setAttribute("page", page);

Date 转换的问题

最开始的时候,我们看到页面上显示的日期是这样的格式:

这显然是我们不希望看到的

  • 解决方案:在映射文件中设置日期显示的类型。

重新部署文件,然后刷新页面,就能看到我们希望的效果啦:

项目总结

  1. 由于之前的项目代码都有,所以在重构的时候,基本上没有花什么时间就完成了项目的搭建,能够体会到代码分离的重要性,这在很大程度上保证了我们的代码复用。
  2. 相较于之前用 Servlet + JSP 来完成,很明显的感觉是DAO层的编写方便了很多,仅仅需要编写一个 xml 映射文件和一个 Dao 层接口就可以完成功能,而不用自己再去重复的去在每一个 CRUD 方法中去处理结果集,重复而且繁琐。
  3. 注解真的很方便,这不仅仅提升了我们自身开发的效率,写起来也很带劲儿。
  4. 开发效率快,而且低耦合,我们基于 xml 配置了大部分的工作,在基于 SSM 框架开发时,我们可以把专注点集中在逻辑处理上。
  5. 在 SSM 框架中能方便的对项目进行修改,这不仅仅得益于框架的约定,使得代码分离并且可复用,也得益于 Maven 工具对于项目的管理。
  6. 我们能够通过一个 Controller 来完成五个 Servlet 的功能,并且通过注解来完成配置。

项目改进

项目很简单,仅仅也只是在数据库增删改查的基础上增加了一个界面,我们来动手改一改。

改进一:增加删除提示

第一个想到的就是删除提示,没有删除提示是很要命的一件事情,如果手滑了一下那可能就悲剧了....

首先我们在顶部的 <head> 标签中的 <script> 中增加一段代码:

function del() {var msg = "您真的确定要删除吗?\n\n请确认!";if (confirm(msg) == true) {return true;} else {return false;}
}

然后在删除 a 标签页中增加 onclick 属性:

onclick="javascript:return del();"
....就像下面这样....
td><a href="/deleteStudent?id=${s.id}" onclick="javascript:return del();"><spanclass="glyphicon glyphicon-trash"></span> </a></td>

当我们刷新页面后,点击删除就会弹出提示信息:

改进二:编辑页面自动勾选上性别

在当前的项目中,如果点击编辑按钮进入到编辑页面后,性别这个选项是空选的状态,这就很low:

这个也很简单,在 editStudent 页面增加一些判断就好了:

<c:if> 标签来判断 sex 的值,然后根据对应的属性增加 checked 属性,这样就可以自动勾选上所对应的属性:

改进三:空值判断

我们允许设置为 null 的值仅仅为出生日期,其他的值均不允许出现空值,所以我们需要加入空值判断:

function checkEmpty(id, name) {var value = $("#" + id).val();if (value.length == 0) {alert(name + "不能为空");$("#" + id).focus();return false;}return true;
}

然后再为 form 创建一个 id 属性值为 “addForm” 并添加进判断空值的方法:

  • 注意: 这里需要写在 $(function(){}) 里面,等待文档加载完毕才能生效。
  • 这里并没有为 sex 属性判断空值,我们采用一个简单的为 sex 添加一个默认勾选项来省略空值的判断。

同样的,我们也在编辑页面,采用同样的方法进行空值判断:

  • 当进入编辑页面的时候已经有默认的勾选项了,所以 sex 值仍然不需要判空
  • 最后给出项目地址:https://github.com/wmyskxz/StudentManager-SSM

我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。

转载于:https://my.oschina.net/u/3721254/blog/1806977

学生管理系统(SSM简易版)总结相关推荐

  1. 初学Java Web(9)——学生管理系统(简易版)总结

    技术准备 这个项目是自己用于巩固 J2EE 相关知识的练手项目,非常简单,但是相关的功能却非常实用,所以在这里分享一下 为了完成这个项目,需要掌握如下技术: Java 基础知识 前端: HTML, C ...

  2. c语言按给定成绩查询,C语言学生成绩管理系统(简易版)

    #include #include #include int readstudents(struct students stu[]); //读取学生信息 int readsexcode(struct ...

  3. 用python3做学生管理系统_详解用python实现基本的学生管理系统(文件存储版)(python3)...

    详解用python实现基本的学生管理系统(文件存储版)(python3) 来源:中文源码网    浏览: 次    日期:2019年11月5日 详解用python实现基本的学生管理系统(文件存储版)( ...

  4. python登录系统文件版_详解用python实现基本的学生管理系统(文件存储版)(python3)...

    这个是升级的版本,比较进阶一点的,相对与之前的文件管理系统,数据只是存储到了内存中,而不是存储到硬盘上,我们想让文件存储到硬盘上的话,一个是存储到文件里,一个是存储到数据库中,存储到数据库中的版本会后 ...

  5. 学生管理系统——C语言版

    文章目录 学生管理系统--C语言版 主函数 录入学生信息 删除学生信息 修改学生信息 查找学生信息 打印学生信息 保存学生信息 读取学生信息 求班级成绩的平均值 学生管理系统--C语言版 主函数 in ...

  6. 学生管理系统(Java版)

    学生管理系统(Java版) 前言:这个是大二做的课设(还是学生管理系统-),理论上虽然是4个人一组一起做的,但是,注意这个"但是",还是我一个人承担了所有-代码和文档基本都是我一个 ...

  7. java学生管理系统(简易)(三)---教师端的登录主页面

    教师端的登录界面就比较清晰了...可能就我自己认为,以为前面写的太乱了...蒙圈 // 学会了先布局,在完善部分代码,嘤嘤嘤...之前那个学生的感觉凉凉啊~ // 有些代码中可能有main函数,有些没 ...

  8. ❤️C语言通讯录管理系统(简易版)❤️

    ❤️C语言通讯录管理系统(简易版)❤️

  9. 学生成绩管理系统(简易版)

    写一个简单的学生成绩管理系统 为了方便,并且这个程序也不是很长,所以把所有代码写在一起了,下面是头文件和声明部分: 4.14修改版 : #include<stdio.h> #include ...

  10. python车辆管理系统_Python简易版停车管理系统

    本文实例为大家分享了Python简易版停车管理系统的具体代码,供大家参考,具体内容如下 import time # 最大停车数 max_car = 100 # 当前停车数,初始为0 cur_car = ...

最新文章

  1. SpringBoot第二十四篇: springboot整合docker
  2. iconv 文件编码转换
  3. jlink烧写Nor Flash时出错正确解决方法汇总:PC of target system has unexpected value after programming (2011
  4. MongoDB分布式操作——分片操作
  5. Java案例:使用clone()方法克隆对象
  6. 根据导出的查询结果拼接字符串,生成sql语句并保存到txt文件中
  7. Flash CS4 Professional 10.0.2简体中文版下载地址
  8. HTML5 九宫格拼图游戏
  9. 平行四边形周长和面积计算c语言,平行四边形的周长公式
  10. 《用计算机写作文》说课稿,《我用电脑写作文》说课稿
  11. 史上最强的烧脑合集!能全都搞懂的只有天才!
  12. 谷歌学术检索论文如何指定多个来源
  13. lsm mysql_一文了解数据库索引:哈希、B-Tree 与 LSM
  14. 【Matlab学习】
  15. jdk1.8的下载与安装教程
  16. 007:Scrapy核心架构和高级运用
  17. 扫一扫,一键生成微信个人数据报告
  18. 《2008胡润IT富豪榜》
  19. 摘自【北京迅为】itop-3568开发板快速启动手册 第二章 Windows安装串口终端
  20. cpp-netlib笔记三-Cookie支持测试

热门文章

  1. 中国电梯行业动态调研与未来发展趋势展望报告2022-2028年版
  2. 随机数排列JAVA_随机数生成器,按排序顺序
  3. 使用脚本安装elasticsearch7.3的记录
  4. Spring Cloud中Hystrix、Ribbon及Feign的熔断关系是什么?
  5. Linux中zip压缩和解压缩命令
  6. WmS详解(一)之token到底是什么?基于Android7.0源码
  7. USACO 2.3 Money Systems(DP)
  8. Client向Server send数据,返回WSAEWOULDBLOCK错误
  9. 必然之势:从结构、时间、媒介的角度看信息的发展趋势
  10. 技术型产品经理与系统设计