表现层(springMVC):Controller层(Handler层)
负责具体的业务模块流程的控制
Controller层通过要调用Service层的接口来控制业务流程,控制的
配置也在Spring配置文件里面。
业务层(Spring):Service层
Service层:负责业务模块的逻辑应用设计。
首先设计其接口,然后再实现他的实现类。
通过对Spring配置文件中配置其实现的关联,完成此步工作,我们
就可以通过调用Service的接口来进行业务处理。
最后通过调用DAO层已定义的接口,去实现Service具体的 实现类。
持久层(Mybatis):Dao层(Mapper层)
Dao层:负责与数据库进行交互设计,用来处理数据的持久化工作。
DAO层的设计首先是设计DAO的接口,
然后在Spring的配置文件中定义此接口的实现类,就可在其他模块中
调用此接口来进行数据业务的处理,而不用关心接口的具体实现类是
哪个类,这里用到的就是反射机制, DAO层的数据源配置,以及有
关数据库连接的参数都在Spring的配置文件中进行配置。
视图层:View层
负责前台jsp页面的展示。
此层需要与Controller层结合起来开发。
各层间的联系:
本来Controller层与View层是可以放在.jsp文件里一起开发的,但是为了降低代码的复杂度,提高其可维护性,将其分为了这两层,这也体现了MVC框架的特性,即结构清晰,耦合度低。
Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。
1、功能点
2、技术点
3、基础环境搭建
3.1、创建一个maven webapp工程
3.2、引入项目依赖的jar包
pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.saogroupId>
<artifactId>MySSMDemoartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.3.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>4.3.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>4.3.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>c3p0groupId>
<artifactId>c3p0artifactId>
<version>0.9.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.41version>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.0.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.8.8version>
dependency>
dependencies>
project>
3.3、引入bootstrap前端框架
将下载的包解压放入项目,以及添加jquery-3.3.1.min.js
4、编写SSM整合的关键配置文件
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
<init-param>
<param-name>forceRequestEncodingparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HttpPutFormContentFilterfilter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
4.3、dispatcherServlet-servlet.xml
<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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.sao" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/">property>
<property name="suffix" value=".jsp">property>
bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
beans>
4.4、applicationContext.xml
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.sao">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.url}">property>
<property name="driverClass" value="${jdbc.driverClass}">property>
<property name="user" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml">property>
<property name="dataSource" ref="pooledDataSource">property>
<property name="mapperLocations" value="classpath:mapper/*.xml">property>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.sao.dao">property>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory">constructor-arg>
<constructor-arg name="executorType" value="BATCH">constructor-arg>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="pooledDataSource">property>
bean>
<aop:config>
<aop:pointcut expression="execution(* com.sao.service..*(..))" id="txPoint"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
<tx:method name="get*" read-only="true"/>
tx:attributes>
tx:advice>
beans>
4.5、jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=true&characterEncoding=UTF-8
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456
4.6、mybatis-config.xml
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<package name="com.sao.entity"/>
typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="reasonable" value="true"/>
plugin>
plugins>
configuration>
5、使用Mybatis-generator插件快速生成代码
Mysql数据库表
5.1、在pom.xml添加如下代码:
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-maven-pluginartifactId>
<version>1.3.2version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xmlconfigurationFile>
<verbose>trueverbose>
<overwrite>trueoverwrite>
configuration>
plugin>
plugins>
build>
5.2、在resources下的generator创建generatorConfig.xml
<generatorConfiguration>
<classPathEntry location="mysql-connector-java-5.1.46-bin.jar"/>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true" />
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm"
userId="root"
password="123456">
jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
javaTypeResolver>
<javaModelGenerator targetPackage="com.sao.entity"
targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources">
<property name="enableSubPackages" value="false" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.sao.dao"
targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
javaClientGenerator>
<table tableName="t_emp" domainObjectName="Employee">table>
<table tableName="t_dept" domainObjectName="Department">table>
context>
generatorConfiguration>
注意:将mysql-connector-java-5.1.46-bin.jar包放入项目
5.3、在plugins中找到mybatis-generator plugin,运行
附上工程目录结构及自动生成的文件
6、根据需求修改mapper文件
6.1、在EmployeeMapper.java添加:
/*自己定义查询,带上部门信息*/
List selectByExampleWithDept(EmployeeExample example);
/*自己定义查询,带上部门信息*/
Employee selectByPrimaryKeyWithDept(Integer id);
6.2、在Employee.java添加:
//希望查询员工信息的同时也可以查询部门信息
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
6.3、在EmployeeMapper.xml中添加:
<resultMap id="WithDeptResultMap" type="com.sao.entity.Employee">
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="gender" property="gender" jdbcType="CHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="d_id" property="dId" jdbcType="INTEGER" />
<association property="department" javaType="com.sao.entity.Department">
<id column="did" property="id" jdbcType="INTEGER" />
<result column="dname" property="name" jdbcType="VARCHAR" />
association>
resultMap>
<sql id="WithDept_Column_List">
e.id, e.name, e.gender, e.email, e.d_id, d.id did, d.name dname
sql>
<select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
select
<if test="distinct" >
distinct
if>
<include refid="WithDept_Column_List" />
from t_emp e
left join t_dept d on e.d_id= d.id
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
if>
<if test="orderByClause != null" >
order by ${orderByClause}
if>
select>
<select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
select
<include refid="WithDept_Column_List" />
from t_emp e
left join t_dept d on e.d_id= d.id
where e.id = #{id,jdbcType=INTEGER}
select>
6、Jsp
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:forward page="/emps">jsp:forward>
views下的list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<script type="text/javascript"
src="${APP_PATH }/static/js/jquery-3.3.1.min.js">script>
<link
href="${APP_PATH }/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="${APP_PATH }/static/bootstrap-3.3.7-dist/js/bootstrap.min.js">script>
head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>SSM-CRUDh1>
div>
div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新增button>
<button class="btn btn-danger">删除button>
div>
div>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<tr>
<th>#th>
<th>empNameth>
<th>genderth>
<th>emailth>
<th>deptNameth>
<th>操作th>
tr>
<c:forEach items="${pageInfo.list }" var="emp">
<tr>
<th>${emp.id }th>
<th>${emp.name }th>
<th>${emp.gender=="M"?"男":"女" }th>
<th>${emp.email }th>
<th>${emp.department.name }th>
<th>
<button class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true">span>
编辑
button>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true">span>
删除
button>
th>
tr>
c:forEach>
table>
div>
div>
<div class="row">
<div class="col-md-6">当前 ${pageInfo.pageNum }页,总${pageInfo.pages }
页,总 ${pageInfo.total } 条记录div>
<div class="col-md-6">
<nav aria-label="Page navigation">
<ul class="pagination">
<li><a href="${APP_PATH }/emps?pn=1">首页a>li>
<c:if test="${pageInfo.hasPreviousPage }">
<li><a href="${APP_PATH }/emps?pn=${pageInfo.pageNum-1}"
aria-label="Previous"> <span aria-hidden="true">«span>
a>li>
c:if>
<c:forEach items="${pageInfo.navigatepageNums }" var="page_Num">
<c:if test="${page_Num == pageInfo.pageNum }">
<li class="active"><a href="#">${page_Num }a>li>
c:if>
<c:if test="${page_Num != pageInfo.pageNum }">
<li><a href="${APP_PATH }/emps?pn=${page_Num }">${page_Num }a>li>
c:if>
c:forEach>
<c:if test="${pageInfo.hasNextPage }">
<li><a href="${APP_PATH }/emps?pn=${pageInfo.pageNum+1 }"
aria-label="Next"> <span aria-hidden="true">»span>
a>li>
c:if>
<li><a href="${APP_PATH }/emps?pn=${pageInfo.pages}">末页a>li>
ul>
nav>
div>
div>
div>
body>
html>
8、Service
EmployeeService .java
public interface EmployeeService {
public List getAll();
}
EmployeeServiceImpl.java
package com.sao.service.impl;
import com.sao.dao.EmployeeMapper;
import com.sao.entity.Employee;
import com.sao.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
* @return
*/
public List getAll() {
return employeeMapper.selectByExampleWithDept(null);
}
}
9、Controller
EmployeeController .java
package com.sao.controller;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sao.entity.Employee;
import com.sao.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* 处理员工CRUD请求
*/
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
/**
* 查询员工数据(分页查询)
* @return
*/
@RequestMapping("/emps")
public String getEmps(@RequestParam(value = "pn", defaultValue = "1")Integer pn, Model model){
// 引入PageHelper分页插件(导包,配置文件配置)
// 在查询之前只需要调用,传入页码,以及每页的大小
PageHelper.startPage(pn, 5);
// startPage后面紧跟的这个查询就是一个分页查询
List emps = employeeService.getAll();
// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。
// 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数
PageInfo page = new PageInfo(emps, 5);
model.addAttribute("pageInfo", page);
return "list";
}
}
10、访问jsp
访问http://localhost:8080/index.jsp将跳转到views下的list.jsp显示列表信息
目前已经实现对信息的分页查询,由于篇幅过长,后续CRUD代码就不再博文中写出;
另外:现在的写法(转发页面)只适用于浏览器与后台交互的模型,如果在安卓,ios端则解析的话比较费劲,所以推荐使用ajax+json的形式向前台传递数据;
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。可以方便的实现数据的跨平台交换。
分页查询-ajax:
1、index.jsp页面直接发送ajax请求进行员工分页数据的查询
2、服务器将查出的数据,以json字符串的形式返回给浏览器
3、浏览器收到js字符串,可以使用js对json进行解析,使用js通过dom增删改改变页面
4、返回json。实现客户端的无关系
EmployeeController .java
@RequestMapping("/emps")
@ResponseBody
public PageInfo getEmpsWithJson(@RequestParam(value = "pn",defaultValue = "1")Integer pn){
// 引入PageHelper分页插件
// 在查询之前只需要调用,传入页码,以及每页的大小
PageHelper.startPage(pn,5);
// startPage后面紧跟的这个查询就是一个分页查询
List employees=employeeService.getAll();
// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。
// 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数
PageInfo pageInfo=new PageInfo(employees,5);
return pageInfo;
}
使用@ResponseBody返回json形式的数据
注意:使用@ResponseBody需要导jar包