SSM框架之初体验

  暑假跟着老师一起学习SSM框架,对于初学者来说,课堂上学的那点java知识,此时显得如此匮乏,也深感知识的不足,跟着网上的教程完成了一个简单的CRUD功能的信息管理项目,仅此为这几天的学习做个总结。

一、初步了解SSM

  SSM=Spring + Spring MVC + Mybatis ,是标准的MVC模式,将整个系统划分为表现层,controller层,service层,DAO层四层,使用spring MVC负责请求的转发和视图管理,spring实现业务对象管理,mybatis作为数据对象的持久化引擎。

二、SSM原理

  关于SSM框架的原理,由于所学尚浅,这里引用csdn博主的见解并加以理解

SpringMVC:
1.客户端发送请求到DispacherServlet(分发器)
2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller
3.Controller调用业务逻辑处理后,返回ModelAndView
4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图

5.视图负责将结果显示到客户端

Spring:我们平时开发接触最多的估计就是IOC容器,它可以装载bean(也就是我们Java中的类,当然也包括service dao里面的),有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。

Mybatis:mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令

以上是该博主对SSM框架的分享,在此之后,我进一步查阅资料了解了该框架下各层级的解释

持久层:DAO层(mapper)
  • DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,

    • DAO层的设计首先是设计DAO的接口,
    • 然后在Spring的配置文件中定义此接口的实现类,
    • 然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,
    • DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置。
业务层:Service层
  • Service层:Service层主要负责业务模块的逻辑应用设计。
    • 首先设计接口,再设计其实现的类
    • 接着再在Spring的配置文件中配置其实现的关联。这样我们就可以在应用中调用Service接口来进行业务处理。
    • Service层的业务实现,具体要调用到已定义的DAO层的接口,
    • Service层的实现类中用Spring的IOC(@Autowired注解)自动注入了一个或多个mapper对象,即该对象是调用sqlSessionFactory的getSession的getBean方法获得的。然后再调用mapper对象的相应方法
表现层:Controller层(Handler层)
  • Controller层:Controller层负责具体的业务模块流程的控制

    • 在此层里面要调用Service层的接口来控制业务流程,
    • 控制的配置也同样是在Spring的配置文件里面进行,针对具体的业务流程,会有不同的控制器,我们具体的设计过程中可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块,这样不仅使程序结构变得清晰,也大大减少了代码量。
  • 至于View层 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示.

Service逻辑层设计
  Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。

整体来说就是,用户request请求到SpringMVC的前端控制器,从处理器映射器找相应的handler(用@RequestMapping(" ")标注,映射成功后,由SpringMVC生成一个handler对象,该对象中有一个方法,即映射成功的该方法),handler中调用的是业务控制层(service)的方法接口。返回有地址和请求参数的ModelAndView对象(其中装载着参数如name,id,和目标地址即相应的显示页面如jsp,用Map存储,然后放到request对象中)到前端控制器,然后前端控制器把ModelAndView传给视图解析器,加上解析器中设置的jsp地址的前缀和后缀,然后把视图返回给前端控制器,再进行视图的渲染(把map中数据填充的request对象中),返回给客户端。

由于接触时间不长,理解浅陋,以照着网上教程做的CRUD为例,回顾一遍

三、CRUD回顾

CRUD功能分解
  • 查询数据库数据,分页显示
  • 添加信息
    • 数据校验,校验用户名和邮箱是否合法
    • 前端jquery校验,后端使用JSR303
  • 修改信息
  • 单个(批量)删除信息
  • ajax请求完成CRUD
  • Rest风格的url
项目搭建

基础框架:SSM,数据库:MySQL,前端框架:Bootstrap快速搭建
Helper(MyBatis工具),逆向工程MyBatis Generator
Maven管理jar包
此项目是在eclipse下进行的,tomcat及maven的配置此处省略

文件配置
  • pom.xml文件,主要为4大类的配置
  • 日志文件
<dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.12</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.1.1</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.1</version>
    </dependency>
  • 数据库依赖
 <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.37</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1.2</version>
    </dependency>
  • DAO框架依赖
<dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.3</version>
    </dependency>
  • Spring相关依赖
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <!--Spring DAO层依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.17.RELEASE</version>
    </dependency>

    <!--Spring test 相关依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.7.RELEASE</version>
    </dependency>
下面是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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    <!-- 跳转逻辑的配置 -->
    <!-- 扫描业务逻辑组件,配置组件扫描器,注解式使用,只扫描控制器-->
    <context:component-scan base-package="com.crud.controller" />
        
    <bean id="mappingJacksonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

        <property name="messageConverters">
            <list>
                <ref bean="mappingJacksonHttpMessageConverter"/>
            </list>
        </property>
    </bean>
    
    
    
    <!-- =============================================================================== -->
    <!-- 2.配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/jsp/" />
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- 两个标准配置 -->
    <!-- 把spirngmvc不能处理的请求交给tomcat 比如静态资源图片等-->
    <mvc:default-servlet-handler/>
    
    <!-- 配置注解驱动 映射动态请求 支持springmvc一些高级功能,比如JSR303校验,快捷AJAX请求-->
    <mvc:annotation-driven/>
</beans>

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:aop="http://www.springframework.org/schema/aop"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd
        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-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    <context:component-scan base-package="com.crud">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <context:property-placeholder location="classpath:dbconfig.properties" />
    <bean id="PooledDataSource"  class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    
    <!-- **********     整合Mybatis       ********** -->
    <!-- 1. 注册SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定mybatis主配置文件的位置 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 连接池注入 -->
        <property name="dataSource" ref="PooledDataSource"/>
        <!-- 指定mapper文件的位置 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
    
    <!-- 扫描器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
         <property name="basePackage" value="com.crud.dao"></property>
    </bean>
    
    <!-- 事务控制  -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="PooledDataSource"></property>
        </bean>
    
    <!-- 可以执行批量的SqlSession  -->
    <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>
    <aop:config>
        <!-- 切入点表达式 -->
        <aop:pointcut expression="execution(* com.crud.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>

下面为我的项目的目录


1.png

这里就不把所有代码贴出来,其中
mapper文件夹下的文件,bean,dao文件是通过mybatis的逆向工程生成的,
Msg是自己创建用来反馈每次用户请求的信息类(其中自定义状态码用来标识请求结果)
test是用来做junit测试用的,分别用来检测框架是否打通,mybatis逆向工程是否生成以及数据库增删及分页是否成功

在这里就几个重要环节做回顾


@Controller
public class StuInfoController {
    
    @Autowired
    StuInfoService stuInfoService;
    
    /**
     * 导入jackson包 把对象转换成JSON字符串 第二稿 支持移动设备
     * 
     * @param pn
     * @return
     */
    
    @RequestMapping("/stuInfo")
    @ResponseBody
    public Msg getStuInfoWithJson(@RequestParam(value="pn",defaultValue="1")Integer pn,Model model) {
                //这是一个分页查询
                // 引入PageHelper分页插件
                // 查询前调用,传入页码和记录数
                PageHelper.startPage(pn, 5);
                // startPage紧跟着的这个查询就是一个分页查询
                List<StuInfo> stuInfos=stuInfoService.getAll();
                // PageInfo包装查询结果,封装了详细的分页信息和详细数据
                // 连续显示5页
                PageInfo pageInfo=new PageInfo(stuInfos,5);
                return Msg.success().add("pageInfo",pageInfo);
    }
     
    @RequestMapping(value = "/stuInfo/{infoIds}", method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmpById(@PathVariable("infoIds") String ids) {
        if (ids.contains("-")) {
            String[] strIds = ids.split("-");
            /*
             * 一种实现 for (String str : strIds) {
             * employeeService.deleteEmp(Integer.parseInt(str)); }
             */
            // 另一种实现
            List<Integer> del_ids = new ArrayList<Integer>();
            for (String str : strIds) {
                del_ids.add(Integer.parseInt(str));
            }
            stuInfoService.deleteAll(del_ids);

        } else {
            stuInfoService.deleteStuInfoId(Integer.parseInt(ids));
        }
        return Msg.success();
    }
    
    
    /**
     * 查询员工数据 分页查询
     * @return
     */
    //@RequestMapping("/stuInfo")
    public String getStuInfo(@RequestParam(value="pn",defaultValue="1")Integer pn,Model model) {
        //这是一个分页查询
        //引入PageHelper 传入页码以及每页的大小
        PageHelper.startPage(pn, 5);
        List<StuInfo> stuInfos=stuInfoService.getAll();
        PageInfo pageInfo=new PageInfo(stuInfos,5);
        model.addAttribute("pageInfo", pageInfo);
        return "list";
    }
}

这里主要是从数据库查询所有的数据,以json数据串的形式返回,再由jquery对数据处理,以表格形式显示在页面(这里没有用bootstrap-table,我想boststrap_table做出来的表格会更好吧),其中分页的具体实现在相应js文件中


2.png

可能描述的不是很清楚,如果有感兴趣的,可以看文章末尾的源码,初学者,写的很烂,请勿见怪。

Controller层其他功能为,这里没有具体的实现
3.png

此外在本项目中有一个小细节

下面为借鉴别人的流程图

  • 由于上图所示表格中编辑删除按钮是页面加载完成后,由ajax发送请求,再添加到页面,所以如果用click绑定事件则不会生效
  • 此时要使用dom对象操作


    index.png

    这其中还有很多大大小小的细节值得我注意,而我还要掌握的东西还有很多很多,在这里可能并不能完全写下,后面会慢慢促使自己养成写总结以及导图的好习惯,希望自己能够有所收获。

在这里感谢很多书友和博主的分享,这里多次引用借鉴你们的文章,如有冒犯,深感抱歉
项目源码地址
https://github.com/luo111/SSM-CRUD

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • SSM框架整合理解 把IntelliJ IDEA+Maven+Spring + SpringMVC + MyBat...
    青年马土豆阅读 9,317评论 0 21
  • 今天是一年一度美食节!!!是全国最大的节日,今天全国各地的游客都会来这里吃美食。这里有各种各样的美食比如说:皮皮虾...
    薛可欣阅读 201评论 0 0
  • 昨夜睡意袭,忽闻林雨声。 欲睹窗外景,虫鸟正嬉逐。 冷风携寒意,旧事沦感伤。 曾与尔相惜,对酒畅言欢。 不及岁月逝...
    乐筱涵阅读 376评论 1 1