技术准备
为了完成这个项目,需要掌握如下技术:
- Java基础知识
- 前端:HTML, CSS, JAVASCRIPT, JQUERY
- J2EE:Tomcat, Servlet, JSP, Filter
- 框架:Spring, Spring MVC, MyBatis, Spring 与 MyBatis 整合, SSM 整合
- 数据库:MySQL
- 开发工具:IDEA, Maven,navicat
开发流程
需求分析
首先要确定要做哪些功能
- 使用mysql数据库来保存数据.
- 能增删改查学生的信息(学号,名称,年龄,性别,出生日期).
表结构设计
根据需求,那么只需要一个 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 AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
MySQL 在 Windows 下不区分大小写,但在 Linux 下默认区分大小写,因此,数据库名、表明、字段名都不允许出现任何大写字母,避免节外生枝。
原型设计
就是设计界面,在商业项目中,这是很重要的一步,我们可以解除界面原型,低成本、高效率的与客户达成需求的一致性。
这个项目一共就分为四个页面:
-
主页面
-
新增学生信息页面
- 编译学生信息页面
- 学生信息列表展示页面
SSM 环境搭建
在真正开始编写代码之前,我们首先需要先来搭建好我们的 SSM 环境。
第一步:创建 Maven webapp 项目
首先新建工程,选择 Maven 标签,然后勾选上【Create from archetype】选择 webapp:
点击下一步,填写上【GroupId】和【ArtifactId】:
- GroupId:项目组织唯一的标识符,实际对应 JAVA 的包的结构,也就是 main 目录下 java 的目录结构(包)。
- AritifactId:项目的唯一标识符,实际对应项目的名称,就是项目根目录的名称。
然后是确认项目路径,可以看到 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"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!-- $Id: pom.xml 642118 2008-03-28 08:04:16Z reinhard $ -->
<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>StudentManager</name>
<groupId>con.netease.cloud</groupId>
<artifactId>StudentManager</artifactId>
<version>1.0-SNAPSHOT</version>
<!--定义变量-->
<properties>
<!-- 设置项目编码编码 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<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>
<build>
<finalName>StudentManager</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<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">
<display-name>学生管理系统</display-name>
<!--首页文件列表-->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--解决中文乱码问题,一定要放在其他所有过滤器之前-->
<filter>
<filter-name>SetCharacterEncoding</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--将spring文件夹下的spring相关的配置文件整合到一起-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/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">
<!-- 配置数据库相关参数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="com.netease.cloud.entity"/>
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/StudentMapper.xml"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置基于注解的声明式事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.netease.cloud.dao"/>
</bean>
<!-- 扫描dao包下所有使用注解的类型 -->
<context:component-scan base-package="com.netease.cloud.dao"/>
<!-- 扫描service包下所有使用注解的类型 -->
<context:component-scan base-package="com.netease.cloud.service"/>
</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="com.netease.cloud.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://127.0.0.1:3306/student?useUnicode=true&characterEncoding=utf8
#用户名
jdbc.username=root
#密码
jdbc.password=123
#最大连接数
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 的相关配置信息(自动扫描
com.netease.cloud
包下的带有注解的类) - 通过 xml 配置的方式配置好了日志和数据库
entity的设计
实体类仅仅是对数据库中表的一一映射(表中字段名应该和实体类中的名称一一对应),同时可能还需要兼顾对业务能力的支持。
在 Packge【com.netease.cloud.entity】下创建 Student 类:
package com.netease.cloud.entity;
import java.util.Date;
/**
* Student 实体类
*
* @author: louxj424
* @create: 2018-12-02-下午 12:03
*/
public class Student {
/**
* 自增主键
*/
private int id;
/**
* 学号
*/
private int studentId;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 性别
*/
private String sex;
/**
* 生日
*/
private Date birthday;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
DAO的设计
DAO,即 Date Access Object,数据库访问对象,就是对数据库相关操作的封装,让其他地方看不到 JDBC 的代码。
在【cn.netease.cloud.dao】包下创建【StudentDao】接口:
package com.netease.cloud.dao;
import com.netease.cloud.entity.Student;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StudentDao {
int getTotal();
int addStudent(Student student);
int deleteStudent(int id);
int updateStudent(Student student);
Student getStudent(int id);
List<Student> list(int start, int count);
}
然后在【resources/mapper】下创建好对应的映射文件【StudengMapper.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="com.netease.cloud.dao.StudentDao">
<resultMap id="BaseResultMap" type="Student">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="student_id" jdbcType="INTEGER" property="studentId"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="age" jdbcType="INTEGER" property="age"/>
<result column="sex" jdbcType="VARCHAR" property="sex"/>
<result column="birthday" jdbcType="TIMESTAMP" property="birthday"/>
</resultMap>
<sql id="Base_Column_List">
id,student_id,name,age,sex,birthday
</sql>
<sql id="Base_Table_Name">
student
</sql>
<!-- 查询一条数据 -->
<select id="getStudent" resultMap="BaseResultMap" parameterType="java.lang.Integer">
SELECT
<include refid="Base_Column_List"/>
FROM
<include refid="Base_Table_Name"/>
WHERE id = #{id,jdbcType=INTEGER}
</select>
<!-- 分页查询:查询从start位置开始的count条数据-->
<select id="list" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM
<include refid="Base_Table_Name"/>
ORDER BY student_id DESC
limit #{param1}, #{param2}
</select>
<!-- 查询数据条目 -->
<select id="getTotal" resultType="java.lang.Integer">
SELECT COUNT(*) FROM
<include refid="Base_Table_Name"/>
</select>
<!-- 增加一条数据 -->
<insert id="addStudent" useGeneratedKeys="true" keyColumn="id" parameterType="Student">
INSERT INTO
<include refid="Base_Table_Name"/>
(id,student_id,name,age,sex,birthday)
VALUES(#{id,jdbcType=INTEGER}, #{studentId,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},
#{age,jdbcType=INTEGER}, #{sex,jdbcType=VARCHAR}, #{birthday,jdbcType=TIMESTAMP})
</insert>
<!-- 删除一条数据 -->
<delete id="deleteStudent" parameterType="java.lang.Integer">
DELETE FROM
<include refid="Base_Table_Name"/>
WHERE id = #{id,jdbcType=INTEGER}
</delete>
<!-- 更新一条数据 -->
<update id="updateStudent" parameterType="Student">
UPDATE
<include refid="Base_Table_Name"/>
SET student_id = #{studentId,jdbcType=INTEGER}, name = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER}, sex = #{sex,jdbcType=VARCHAR},
birthday = #{birthday,jdbcType=TIMESTAMP}
WHERE id= #{id,jdbcType=INTEGER}
</update>
</mapper>
编写好了 Dao 类是需要测试的,编写BaseTest和StudentDaoTest类:
package com.netease.cloud;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-mybatis-test.xml"})
@Transactional
public class BaseTest {
}
package com.netease.cloud.dao;
import com.netease.cloud.BaseTest;
import com.netease.cloud.entity.Student;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
public class StudentDaoTest extends BaseTest {
private static final Logger logger = LoggerFactory.getLogger(StudentDaoTest.class);
private static final Integer ID = 65523;
@Autowired
private StudentDao studentDao;
@Test
public void testAdd() {
Student student = new Student();
student.setId(ID);
student.setStudentId(20142126);
student.setName("lou");
student.setAge(12);
student.setSex("男");
student.setBirthday(new Date());
int ret = studentDao.addStudent(student);
assertEquals(1, ret);
}
@Test
public void testSelect() {
testAdd();
Student student = studentDao.getStudent(ID);
assertNotSame(0, student.getId());
}
@Test
public void testUpdate() {
testAdd();
Student student = studentDao.getStudent(ID);
student.setAge(100);
studentDao.updateStudent(student);
assertSame(100, student.getAge());
}
@Test
public void testDelete() {
testAdd();
int ret = studentDao.deleteStudent(ID);
assertEquals(1, ret);
}
@Test
public void testGetTotal() {
testAdd();
int ret = studentDao.getTotal();
assertNotSame(0, ret);
}
@Test
public void testList() {
testAdd();
List<Student> studentList = studentDao.list(0, 1);
assertNotSame(0, studentList.size());
}
}
service的设计
问题: 为什么不直接使用 Dao 类而是还要在上面封装一层 Service 层呢?
回答:基于责任分离的原则,Dao 层就应该专注于对数据库的操作,而在 Service 层我们可以增加一些非 CRUD 的方法去更好的完成本身抽离出来的 service 服务(业务处理)。
在【com.netease.cloud.service】包下创建【StudentService】接口:
package com.netease.cloud.service;
import com.netease.cloud.entity.Student;
import java.util.List;
public interface StudentService {
/**
* 获取到 Student 的总数
*
* @return
*/
int getTotal();
/**
* 增加一条数据
*
* @param student
*/
int addStudent(Student student);
/**
* 删除一条数据
*
* @param id
*/
int deleteStudent(int id);
/**
* 更新一条数据
*
* @param student
*/
int updateStudent(Student student);
/**
* 找到一条数据
*
* @param id
* @return
*/
Student getStudent(int id);
/**
* 列举出从 start 位置开始的 count 条数据
*
* @param start
* @param count
* @return
*/
List<Student> list(int start, int count);
}
并在相同包名下新建一个文件夹【impl】并在该文件夹下创建实现类【StudentServiceImpl】实现接口【StudentService】:
package com.netease.cloud.service.impl;
import com.netease.cloud.dao.StudentDao;
import com.netease.cloud.entity.Student;
import com.netease.cloud.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* StudentService 的实现类
*/
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
public int getTotal() {
return studentDao.getTotal();
}
public int addStudent(Student student) {
return studentDao.addStudent(student);
}
public int deleteStudent(int id) {
return studentDao.deleteStudent(id);
}
public int updateStudent(Student student) {
return studentDao.updateStudent(student);
}
public Student getStudent(int id) {
return studentDao.getStudent(id);
}
public List<Student> list(int start, int count) {
List<Student> studentList = studentDao.list(start, count);
if (studentList == null) {
studentList = Collections.emptyList();
}
return studentList;
}
}
功能开发
在【com.netease.cloud.controller】包下创建【StudentController】控制器:
package com.netease.cloud.controller;
import com.netease.cloud.Const;
import com.netease.cloud.entity.Student;
import com.netease.cloud.service.StudentService;
import com.netease.cloud.util.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.util.Date;
import java.util.List;
/**
* Student 控制器
*
* @create: 2018-12-02-下午 16:43
*/
@Controller
@RequestMapping("")
public class StudentController {
private static final Logger logger = LoggerFactory.getLogger(StudentController.class);
@Autowired
private StudentService studentService;
@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("/addStudent")
public String addStudent(HttpServletRequest request, HttpServletResponse response) {
Student student = new Student();
int studentID = Integer.parseInt(request.getParameter("studentId"));
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
String sex = request.getParameter("sex");
Date birthday = null;
try {
birthday = Const.DATE_FORMAT.parse(request.getParameter("birthday"));
} catch (ParseException e) {
logger.error(e.getMessage());
}
student.setStudentId(studentID);
student.setName(name);
student.setAge(age);
student.setSex(sex);
student.setBirthday(birthday);
studentService.addStudent(student);
return "redirect: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("/showAddStudent")
public ModelAndView showAddStudent() {
ModelAndView mav = new ModelAndView("showAddStudent");
return mav;
}
@RequestMapping("/updateStudent")
public String updateStudent(HttpServletRequest request, HttpServletResponse response) {
Student student = new Student();
int id = Integer.parseInt(request.getParameter("id"));
int studentId = Integer.parseInt(request.getParameter("studentId"));
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
String sex = request.getParameter("sex");
Date birthday = null;
try {
birthday = Const.DATE_FORMAT.parse(request.getParameter("birthday"));
} catch (ParseException e) {
e.printStackTrace();
}
student.setId(id);
student.setStudentId(studentId);
student.setName(name);
student.setAge(age);
student.setSex(sex);
student.setBirthday(birthday);
studentService.updateStudent(student);
return "redirect:listStudent";
}
}
编辑【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 del() {
var msg = "您真的确定要删除吗?\n\n请确认!";
if (confirm(msg) == true) {
return true;
} else {
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.studentId}</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}" onclick="javascript:return del();"><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>
</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>
<script>
$(function () {
$("#editForm").submit(function () {
if (!checkEmpty("studentId", "学号"))
return false;
if (!checkEmpty("name", "姓名"))
return false;
if (!checkEmpty("age", "年龄"))
return false;
return true;
});
});
function checkEmpty(id, name) {
var value = $("#" + id).val();
if (value.length == 0) {
alert(name + "不能为空");
$("#" + id).focus();
return false;
}
return true;
}
</script>
</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" id="editForm" action="/updateStudent" role="form">
<table class="editTable">
<tr>
<td>学号:</td>
<td><input type="text" name="studentId" id="studentId" value="${student.studentId}"
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" <c:if test="${student.sex == '男'}">checked</c:if> class="radio radio-inline" name="sex" value="男"> 男
<input type="radio" <c:if test="${student.sex == '女'}">checked</c:if> 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>
编辑【showAddStudent.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;
});
$("#addForm").submit(function () {
if (!checkEmpty("studentId", "学号"))
return false;
if (!checkEmpty("name", "姓名"))
return false;
if (!checkEmpty("age", "年龄"))
return false;
return true;
});
});
function checkEmpty(id, name) {
var value = $("#" + id).val();
if (value.length == 0) {
alert(name + "不能为空");
$("#" + id).focus();
return false;
}
return true;
}
</script>
</head>
<body>
<!--新增学生视图-->
<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" id="addForm" action="/addStudent" role="form">
<table class="addTable">
<tr>
<td>学号:</td>
<td><input type="text" name="studentId" id="studentId" 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" checked 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>
项目总结
- 相较于之前用 Servlet + JSP 来完成,很明显的感觉是DAO层的编写方便了很多,仅仅需要编写一个 xml 映射文件和一个 Dao层接口就可以完成功能,而不用自己再去重复的去在每一个 CRUD 方法中去处理结果集,重复而且繁琐。
- 注解真的很方便,有助于提升开发效率。
- SSM开发效率快,而且低耦合。基于 xml 配置了大部分的工作,在基于 SSM 框架开发时,可以把专注点集中在逻辑处理上。
- 在 SSM 框架中能方便的对项目进行修改,这不仅仅得益于框架的约定,使得代码分离并且可复用,也得益于 Maven 工具对于项目的管理。
- 能够通过一个 Controller 来完成五个 Servlet 的功能,并且通过注解来完成配置。