zoukankan      html  css  js  c++  java
  • 学生管理系统(SSM简易版)总结

    之前用 Servlet + JSP 实现了一个简易版的学生管理系统,在学习了 SSM 框架之后,我们来对之前写过的项目重构一下!

    技术准备

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

    开发流程

    之前虽然已经使用 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/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://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/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://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 实体类
     *
     * @author: @我没有三颗心脏
     * @create: 2018-04-23-下午 13:34
     */
    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 {
    
        @Autowired
        StudentDao 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 {
    
        @Autowired
        private 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>>
                        <a
                                href="?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 {
         600px;
        margin: 0 auto;
    }
    
    div.editDIV {
         400px;
        margin: 0 auto;
    }
    
    nav.pageDIV {
        text-align: center;
    }
    
    div.addDIV {
         300px;
        margin: 0 auto;
    }
    
    table.addTable {
         100%;
        padding: 5px;
    }
    
    table.addTable td {
        padding: 5px;
    }
    
    table.editTable {
         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页
            else
                totalPage = total / count + 1;
    
            if(0==totalPage)
                totalPage = 1;
            return totalPage;
    
        }
    
        public int getLast(){
            int last;
            // 假设总数是50,是能够被5整除的,那么最后一页的开始就是40
            if (0 == total % count)
                last = total - count;
                // 假设总数是51,不能够被5整除的,那么最后一页的开始就是50
            else
                last = 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 - 1 ,varStatus 相当于是循环变量

    • 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>>
                <a
                        href="?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 = "您真的确定要删除吗?
    
    请确认!";
        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();"><span
            class="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 添加一个默认勾选项来省略空值的判断。

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

     
  • 相关阅读:
    AtCoder Grand Contest 015 题解
    AtCoder Grand Contest 014 题解
    AtCoder Grand Contest 013 题解
    AtCoder Grand Contest 012 题解
    AtCoder Grand Contest 011 题解
    AtCoder Grand Contest 010 题解
    AtCoder Grand Contest 009 题解
    NOIP2017 Day2 题解
    博客园主题备份
    多项式全家桶
  • 原文地址:https://www.cnblogs.com/yelanggu/p/10202297.html
Copyright © 2011-2022 走看看