SSM框架详细实例讲解

SSM框架简介

SSM框架,是Spring + Spring MVC + MyBatis的缩写,这个是继SSH之后,目前比较主流的Java EE企业级框架,适用于搭建各种大型的企业级应用系统。 我们先大概的回顾一下吧。

1.Spring简介 

        Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 

      A.控制反转(IOC)是什么呢? 
        IOC:控制反转也叫依赖注入。利用了工厂模式将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类(假设这个类名是A),分配的方法就是调用A的setter方法来注入,而不需要你在A里面new这些bean了。 
        [注意]:面试的时候,如果有条件,画图,这样更加显得你懂了 
      B.面向切面(AOP)又是什么呢? 
        首先,需要说明的一点,AOP只是Spring的特性,它就像OOP一样是一种编程思想,并不是某一种技术,AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。 
        实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。 
[简单点解释],比方说你想在你的biz层所有类中都加上一个打印‘你好,AOP’的功能这你经可以用aop思想来做,你先写个类写个方法,方法经实现打印‘你好,AOP’让后你Ioc这个类 ref=“biz.*”让每个类都注入。 

2.Spring MVC简介 

        Spring MVC属于Spring Framework的后续产品,已经融合在Spring Web Flow里面,它原生支持的Spring特性,让开发变得非常简单规范。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。 

3.MyBatis简介 

        MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。可以这么理解,MyBatis是一个用来帮你管理数据增删改查的框架。

 

先看一下项目的结构吧

 

说了这么多,现在回归正题,SSM框架里面有很多繁杂的配置,一共有三个

1.web.xml

2.spring.xml

3.mvc-servlet.xml

下面将会依次详细介绍三个配置文件的配置方法以及配置的含义

1.web.xml

web.xml是ssm项目当中最重要的一个配置文件,当服务启动时会首先加载web.xml这个文件,里面包括了对前端控制器、乱码等的配置

下面贴上代码,代码当中有详细的注释解释每个配置的意思

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!--spring的配置-->
<!--==================================================-->
  <!-- 配置srping的位置 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
  </context-param>
  <!-- 配置监听器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!--springmvc需要配置的-->
  <!--==================================================-->

  <!-- 配置springmvc的核心控制器 -->
  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:mvc-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- 解决乱码的配置 -->
  <filter>
    <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- 请求method支持 put和delete必须添加过滤器 -->
  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!--&lt;!&ndash; 启用druid的监控功能 &ndash;&gt;-->
  <servlet>
    <servlet-name>statViewServlet</servlet-name>
    <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    <init-param>
      <param-name>loginUsername</param-name>
      <param-value>admin</param-value>
    </init-param>
    <init-param>
      <param-name>loginPassword</param-name>
      <param-value>admin</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>statViewServlet</servlet-name>
    <url-pattern>/druid/*</url-pattern>
  </servlet-mapping>
</web-app>

2.spring.xml

spring.xml的作用是为了给spring进行配置

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
	http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">

<!-- 扫描cn -->
    <context:component-scan base-package="cn">
        <!-- spring是bean的容器(spring用来操做 service+repository)controler是springmvc操作的 所以排除-->
        <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />-->
    </context:component-scan>

    <!-- 扫描jdbc文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!--
    所有数据库操作的源头 实现自接口DataSouce DriverManagerDataSource
     还有很多连接池继承DataSouce DriverManagerDataSource 实现了很多子连接池 比如c3p0 dbcp druid
     这里我们就用阿里的druid,因为这个连接池有一个监控功能
    -->
    <!-- 连接数据库 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}"></property>
        <property name="driverClassName" value="${driverClass}"></property>
        <property name="username" value="${username1}"></property>
        <property name="password" value="${password1}"></property>
        <!-- 默认初始化的连接个数 -->
        <property name="initialSize" value="1"></property>
        <!-- 最大允许的连接个数 -->
        <property name="maxActive" value="200"></property>
        <!-- 最大的等待人数 -->
        <property name="maxIdle" value="100"></property>
        <!-- 开启sql统计功能 -->
        <property name="filters" value="stat"></property>
    </bean>


    <!-- 事务管理器  不再使用jdbc的commit和rollback 必须由事务管理器提供 配置事物管理器必须要注入dataSource-->
    <bean id="tm"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 定义事物里面的通知-->
    <tx:advice id="txAdvise" transaction-manager="tm">
        <tx:attributes>
            <!--tx:method的作用是拦截指定方法开头的 然后对他进行事物处理 -->
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <!--read-only="true" 意思是除了上面拦截的以外  其他的都不拦截-->
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!-- 定义切点(搜索条件) aop:pointcut 意思相当于跟if差不多 满足条件的就会进来
      表示式   execution(返回值  包.类.方法(参数 ...代表任意多个参数))
      id 表示切点的名字
   -->
        <aop:pointcut expression="execution(* cn.et.service.*.*(..))" id="myPointCut" />
        <!-- 关联切点和事务管理器 将事物跟切点连接起来-->
        <aop:advisor advice-ref="txAdvise" pointcut-ref="myPointCut" />
    </aop:config>


    <!-- 集成mybatis -->
    <!-- 实例化一个SqlSessionFactory工厂-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--指定数据源-->
        <property name="dataSource" ref="dataSource"></property>
        <!--指定实体文件所在的位置-->
        <property name="typeAliasesPackage" value="cn.et.model"/>
        <!--指定mapper.xml文件所在的位置-->
        <property name="mapperLocations" value="classpath:mapper/*.xml" />
    </bean>

    <!-- 扫描mybatis的接口映射文件  -->
    <bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.et.mapper"></property>
    </bean>
</beans>

3.mvc-servlet.xml

mvc-servlet.xml是为了配置springMVC

<?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:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
">
    <!-- 扫描cn -->
    <context:component-scan base-package="cn">
        <!-- pringmvc主要操作控制层、视图层所以给不相关的层次的注解排除-->
        <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>-->
        <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
    </context:component-scan>

    <!--如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。-->
    <mvc:default-servlet-handler/>

    <!-- 引用返回对象 响应json的消息转换器 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html</value>
                        <value>application/x-www-form-urlencoded</value>
                    </list>
                </property>
            </bean>
            <!-- 配置返回对应解析成json的消息转换器 -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html</value>
                        <value>application/x-www-form-urlencoded</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
</beans>

小提示
关于配置文件这个东西,在初学各种框架的时候非常让人头疼,一不小心配置错误,项目就运行不了。所以不如直接从网上找个小项目的源码把代码删除,直接用别人的配置来做练习,在框架能熟练运用之后再慢慢学习配置文件的问题。

据本人亲自整合,在jar包导入完全的时候,上面的这些配置文件可直接使用(数据库连接参数被删除,包名和一些路径的配置根据自己项目来进行更改)

 

到此我们的SSM环境也就搭建好了,现在就要去实现业务的代码了

1.model层是实体类,属性对应数据库表的每个字段,并且我们使用驼峰规则命名属性(这里很重要,字段userName和UserName在封装时差别很大,会映射不到mapper层的xml上),我们一贯的做法会让model序列化,这里虽然没有并发的情况,但是这是一种良好的做法。代码如下:

package cn.et.model;

public class Student {
    private String id;
    private String name;
    private String age;
    private String sex;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

2.mapper层,这里实现和数据库直接交互的接口,@Repository的注解目的是持久化数据层。在这里为了同时将mybatis注解写sql跟xml写sql表现出来,我有的接口用的是注解实现的有的接口用的是xml实现的代码如下:

package cn.et.mapper;

import cn.et.model.Student;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface StudentMapper {
     /**
      * 添加
      * @param student
      */
     void insertStudent(@Param("student") Student student);

     /**
      * 删除
      * @param id
      */
     @Delete("delete from student where sid=#{id}")
     void deleteStudent(@Param("id") String id);

     /**
      * 修改
      * @param student
      */
     void updateStudent(@Param("student") Student student);


     /**
      * 查询所有
      * @return
      */
    @Results({
        @Result(column = "sid",property = "id"),
        @Result(column = "sname",property = "name"),
        @Result(column = "sage",property = "age"),
        @Result(column = "ssex",property = "sex")
    })
    @Select("select * from student")
    List<Student> studentList();

     /**
      * 根据id查询单个
      * @param id
      * @return
      */
     @Results({
             @Result(column = "sid",property = "id"),
             @Result(column = "sname",property = "name"),
             @Result(column = "sage",property = "age"),
             @Result(column = "ssex",property = "sex")
     })
     @Select("select * from student where sid=#{id}")
    Student studentById(@Param("id") String id);

     /**
      * 根据条件查询
      * @param student
      * @return
      */
    List<Student> studentQuery(@Param("student") Student student);


}

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" >
<mapper namespace="cn.et.mapper.StudentMapper" >
    <resultMap id="studentMap" type="cn.et.model.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="age" column="sage"/>
        <result property="sex" column="ssex"/>
    </resultMap>

    <insert id="insertStudent">
        INSERT INTO student (sid,sname,sage,ssex) VALUES (#{student.id},#{student.name},#{student.age},#{student.sex})
    </insert>

    <update id="updateStudent">
      UPDATE student
      <set>
          <if test="student.name !=null and student.name !=''">
              sname=#{student.name},
          </if>
          <if test="student.age !=null and student.age !=''">
              sage=#{student.age},
          </if>
          <if test="student.sex !=null and student.sex !=''">
              ssex=#{student.sex},
          </if>
      </set>
      WHERE sid =#{student.id}
    </update>

    <select id="studentQuery" resultMap="studentMap">
        select * from student
        <where>
            <if test="student.name !=null and student.name !=''">
                and sname like '%${student.name}%'
            </if>
            <if test="student.age !=null and student.age !=''">
                and sage=#{student.age}
            </if>
            <if test="student.sex !=null and student.sex !=''">
                and ssex=#{student.sex}
            </if>
        </where>
    </select>

</mapper>


3.service层,这是用来处理业务的,代码如下:

package cn.et.service;

import cn.et.model.Student;

import java.util.List;

public interface StudentService {
    /**
     * 添加
     * @param student
     */
    void insertStudent(Student student);

    /**
     * 删除
     * @param id
     */
    void deleteStudent(String id);

    /**
     * 修改
     * @param student
     */
    void updateStudent(Student student);


    /**
     * 查询所有
     * @return
     */
    List<Student> studentList();

    /**
     * 根据id查询单个
     * @param id
     * @return
     */
    Student studentById(String id);

    /**
     * 根据条件查询
     * @param student
     * @return
     */
    List<Student> studentQuery(Student student);

}

4.serviceImpl层是service的实现类,@Service注解告诉Spring这是个业务层,Service中声明了几个接口,我们并没有去真正去实现,但是有人想为什么不直接写个实现类,反而要加一个Service层呢?这个问题,这要归结到代码复用性和维护性问题,如果你直接写一个实现,当你增加新的功能时就要在一大堆代码中是添加修改,这是非常耗时的操作,所以接口和实现分离有利于维护,代码如下:
 

package cn.et.service.impl;

import cn.et.mapper.StudentMapper;
import cn.et.model.Student;
import cn.et.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    StudentMapper studentMapper;

    public void insertStudent(Student student) {
        studentMapper.insertStudent(student);
    }

    public void deleteStudent(String id) {
        studentMapper.deleteStudent(id);
    }

    public void updateStudent(Student student) {
        studentMapper.updateStudent(student);
    }

    public List<Student> studentList() {
        List<Student> students = studentMapper.studentList();
        return students;
    }

    public Student studentById(String id) {
        return studentMapper.studentById(id);
    }

    public List<Student> studentQuery(Student student) {
        return studentMapper.studentQuery(student);
    }
}

 

5.控制层Controller 
使用@Controller注解,然后使用@AutoWired导入service层,因为service中的方法是我们使用到的,controller通过接收前端传过来的参数进行业务操作,在返回一个指定的路径或者数据表。RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据,需要注意的呢,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。上面讲的这些都是Spring MVC知识,如果你看不懂请百度Spring MVC流程控制,基础知识我就不多废话。具体代码如下:

package cn.et.controller;

import cn.et.model.Student;
import cn.et.service.StudentService;
import cn.et.tool.CommonResponse;
import cn.et.tool.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class StudentController {
    @Autowired
    StudentService studentService;

    @RequestMapping("insertStudent")
    public Response insertStudent(Student student){
        studentService.insertStudent(student);
        return Response.success();
    }

    @RequestMapping("deleteStudent")
    public Response deleteStudent(String id){
        studentService.deleteStudent(id);
        return Response.success();
    }

    @RequestMapping("updateStudent")
    public Response updateStudent(Student student){
        studentService.updateStudent(student);
        return Response.success();
    }

    @RequestMapping("studentList")
    public Response studentList(){
        List<Student> students = studentService.studentList();
        return new CommonResponse<List<Student>>(students);
    }

    @RequestMapping("studentById")
    public Response studnetById(String id){
        Student student = studentService.studentById(id);
        return new CommonResponse<Student>(student);
    }

    @RequestMapping("studentQuery")
    public Response studentQuery(Student student){
        List<Student> students = studentService.studentQuery(student);
        return new CommonResponse<List<Student>>(students);
    }

}

至此我们的后台代码就告一段落了,如有疑问的小伙伴给我留言。。。。。。。。

  • 21
    点赞
  • 122
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值