> 文章列表 > 做SSM项目的步骤和优化

做SSM项目的步骤和优化

做SSM项目的步骤和优化

SSM框架整合

这里说的SSM整合,主要说的是Spring和mybatis之间的整合。因为spring和springMVC都是spring生态系统中的框架,所以spring和springMVC之间的整合是无缝的整合,即,我们在不知不觉中,其实spring和springMVC已经整合好了,不用你做什么额外的事情了。但是mybatis是第三方的框架,所以我们要手动把spring和mybatis进行整合。

原始整合,即,我们每一层之前怎么学的(mybatis管理dao层,springMVC管理view层),这里就怎么直接用。但是原始整合,你会发现这种整合中,spring和mybatis的整合度不是很高。所以我们之后会解决这些问题,这些问题解决了,SSM框架的整合就已经OK了。这里,我们先学原始的整合方式,然后我们解决原始整合方式存在的问题,解决完了,我们本节“SSM框架整合”的学习就结束了。

原始整合方式

原始整合方式,就是我们直接用SSM框架来做web项目,所以整合的步骤:无。即,你想怎么写这个项目,就怎么写,该用框架的时候就直接用框架来写代码就行了。

没有整合的步骤,那我们来看看我们平常写项目的步骤就行了,平常写项目的步骤做完了,原始整合就结束了。

下面用一个例子来做演示:

步骤:

  1. 编写数据库和表

    建库如下:

    做SSM项目的步骤和优化

    建表如下:

    做SSM项目的步骤和优化

  2. 创建maven项目,并且创建maven工程可能需要的包。反正就是把项目的结构搭好。

    做SSM项目的步骤和优化

  3. 导入项目可能需要用到的架包

    <?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/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.itcast</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.5.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.5.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.5.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.5.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.5.RELEASE</version></dependency><!--servlet和jsp--><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version></dependency><!--mybatis相关的架包--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!--这个mybatis-spring是我们之后优化整合的时候会用,原始整合不用。-->
    <!--    <dependency>-->
    <!--      <groupId>org.mybatis</groupId>-->
    <!--      <artifactId>mybatis-spring</artifactId>-->
    <!--      <version>1.3.1</version>-->
    <!--    </dependency>--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><!--source 和 target根据个人需要自己修改--><source>11</source><target>11</target></configuration></plugin></plugins></build>
    </project>
    
  4. 编写实体类

    实体类如下:

    package com.itcast.domain;public class Account {//建议写Integer,而不是写intprivate Integer id;private String name;private Double money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}
    }
    

    注意点:

    实体类用定义属性的时候,建议包装类型来定义。理由如下:

    做SSM项目的步骤和优化

  5. 编写Mapper接口和可能会用到的方法

    package com.itcast.mapper;import com.itcast.domain.Account;
    import java.util.List;public interface AccountMapper {public void save(Account account);public List<Account> findAll();
    }
  6. 编写Service层的接口和可能会用到的方法

    package com.itcast.service;import com.itcast.domain.Account;
    import java.util.List;public interface AccountService {public void save(Account account);public List<Account> findAll();
    }
    
  7. 编写Service层的接口实现类和实现方法

    package com.itcast.service.impl;import com.itcast.domain.Account;
    import com.itcast.service.AccountService;
    import java.util.List;public class AccountServiceImpl implements AccountService {@Overridepublic void save(Account account) {}@Overridepublic List<Account> findAll() {return null;}
    }
    

    service实现类的具体实现,我们先空着,之后写。

    做SSM项目的步骤和优化

  8. 编写Controller

    这里我们具体实现也先空着。先把框架搭好。

    做SSM项目的步骤和优化

  9. 编写前端的页面

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    注意:

    因为WEB-INF下的资源是受保护的,所以我们不能直接访问到。我们放在WEB-INF文件夹外的资源,我们可以浏览器输入地址直接访问。但是在WEB-INF文件夹内的资源,我们只能通过controller的转发机制访问。

  10. 编写配置文件(这些配置文件的结构先搭好,里面具体写什么得用得时候才知道,所以我们先空着)

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

  11. 补齐配置文件中的配置:

    AccountMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.itcast.mapper.AccountMapper"><insert id="save" parameterType="account">insert into account value(#{id},#{name},#{money})</insert><select id="findAll" resultType="Account">select * from account</select>
    </mapper>
    

    applicationContext.xml

    <?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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    "><!--组件扫描 --><context:component-scan base-package="com.itcast"><!--我们扫这个com.itcast包,那么com.itcast包下的@Controller注解也会被扫描到,但是这个@Controller注解的类一般是表示层的类,所以我们到时候应该让他被springmvc来管理的,所以我们这里spring就不去控制它了,我们就需要这个@Controller注解给排除掉去,到时候让springmvc的配置文件来扫描--><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
    </beans>
    

    jdbc.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm
    jdbc.username=root
    jdbc.password=815924
    

    log4j.properties

    ### direct log messages to stdout ###
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n### direct messages to file mylog.log ###
    #log4j.appender.file=org.apache.log4j.FileAppender
    #log4j.appender.file.File=hibernate.log
    #log4j.appender.file.layout=org.apache.log4j.PatternLayout
    #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n### set log levels - for more verbose logging change 'info' to 'debug' ###log4j.rootLogger=all, stdout
    

    spring-mvc.xml

    <?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--组件扫描,主要扫描@Controller注解--><context:component-scan base-package="com.itcast.controller" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!--配置mvc注解驱动--><mvc:annotation-driven/><!--配置内部资源视图解析器--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/pages/"></property><property name="suffix" value=".jsp"></property></bean><!--开放静态资源访问--><mvc:default-servlet-handler/>
    </beans>
    

    sqlMapConfig.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--加载properties文件--><properties resource="jdbc.properties"></properties><!--定义别名--><typeAliases><!--<typeAlias type="com.itcast.domain.Account" alias="account"></typeAlias>--><!--上面这种定义别名的方式是,把这个com.itcast.domain.Account定义一个别名,别名叫account--><!--下面我们介绍另一种定义别名的方式,扫描包的方式。比如下面这样写的话,我们这个com.itcast.domain包下所有的类都将会被设置别名。设置什么别名,看例子:比如,我们这个com.itcast.domain包下有一个Account类和User类,那么,你用了下面这个扫描包的这个方式,就相当于给这个com.itcast.domain包下的Account类设置了account和Account两个别名。给com.itcast.domain包下的User类设置了User和user两个别名--><package name="com.itcast.domain"></package></typeAliases><!--数据源环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--加载映射文件--><mappers><!--<mapper resource="com\\itcast\\mapper\\AccountMapper.xml"/>--><!--上面这个加载映射文件的方式是一个个加载的,所以,要想加载多个映射文件,你得写多个mapper标签。下面,我们来介绍另一种写法,包引入方式,我们在“mybatis-day1.md”中的mappers标签里面讲过,但是使用这种方式有一些注意点,你看之前“mybatis-day1.md”中的mappers标签的笔记就行. --><package name="com.itcast.mapper"/></mappers>
    </configuration>
    
  12. 完成逻辑代码的编写

    package com.itcast.controller;import com.itcast.domain.Account;
    import com.itcast.service.AccountService;
    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.ResponseBody;
    import org.springframework.web.servlet.ModelAndView;import java.util.List;@Controller
    @RequestMapping("/account")
    public class AccountController {@Autowiredprivate AccountService accountService;//保存(实际中,我们保存成功应该会跳转到一个列表页面的,这里我们简单点,就直接在页面打印一个字符串意思一下。)@RequestMapping("/save")@ResponseBodypublic String save(Account account){accountService.save(account);return "保存成功!";}//查询。查询结束我们返回一个数据,并且返回一个视图。public ModelAndView findAll(){List<Account> accountList=accountService.findAll();ModelAndView modelAndView=new ModelAndView();modelAndView.addObject("accountList",accountList);modelAndView.setViewName("accountList");return modelAndView;}
    }
    package com.itcast.service.impl;import com.itcast.domain.Account;
    import com.itcast.mapper.AccountMapper;
    import com.itcast.service.AccountService;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.springframework.stereotype.Service;import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;@Service("accountService")
    public class AccountServiceImpl implements AccountService {@Overridepublic void save(Account account) {try {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);mapper.save(account);sqlSession.commit();sqlSession.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic List<Account> findAll() {try {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);List<Account> accountList = mapper.findAll();sqlSession.close();return accountList;} catch (IOException e) {e.printStackTrace();}return null;}
    }
    
  13. 测试

    做SSM项目的步骤和优化

    结果:

    做SSM项目的步骤和优化

    数据库:

    做SSM项目的步骤和优化

    发现,页面显示的时候出现了乱码,但是数据库里面存数据的时候是正确的。

    分析:

    数据库能正确存数据的原因是:我们在web.xml中设置了乱码过滤器,所以服务器获取前端代码的数据的乱码问题解决了,即,我们前端输入了中文的数据,后端正确获取到了中文数据,没有出现乱码,然后存到数据库里面,所以数据库里面存的是正确的。

    那么前端出现乱码的原因是什么呢?你看我们之前没用ssm的时候,我们都直接在servlet的代码块的后半段设置response.setContentType(“text/html;charset=utf-8”)。这样前端页面就不会出现乱码了,这里我们ssm要达到这个效果,我们也得设置一下响应的编码。

    解决方法如下:

    做SSM项目的步骤和优化

    测试:

    做SSM项目的步骤和优化

    点击"保存"后:

    做SSM项目的步骤和优化

    数据库数据如下:

    做SSM项目的步骤和优化

  14. 下面我们来完成保存的方法。之前1~13步中,没有把save()方法和他跳转的页面完成,下面我们来把他们完成。

    做SSM项目的步骤和优化

    做SSM项目的步骤和优化

  15. 测试:

    做SSM项目的步骤和优化

原始整合方式的弊端

弊端:

你看上面这里service层中,每次执行某个方法的时候都会执行下面这些语句,即,都会加载配置文件、创建工厂对象、创建Session对象、事务提交、关闭sql会话等。

做SSM项目的步骤和优化

解决:

把创建Session工厂的工作、创建AccountMapper对象的工作都交给spring容器来做。并且把事务控制也交给spring来做。

做SSM项目的步骤和优化

即,我们要做到让spring创建这个AccountMapper,并且注入到这个AccountServiceImpl的某个AccountMapper类型的成员变量里面,然后这个AccountServiceImpl类里面的所有方法都可以用那个成员变量了,这个类里面也不用创建对象,因为创建对象和绑定到AccountServiceImpl的成员变量的工作都交给spring容器了。

然后我们在spring核心配置文件里面给这个AccountServiceImpl类里面的方法配置上事务控制,这样,那些被设置了事务控制的方法会在执行成功的时候自动提交,执行失败的时候自动回滚了,就取代了我们上面的sqlSessioni.commit()和sqlSessioni.close()了。其实上面这个例子里面,出现异常回滚的代码都没有写,我们通过spring核心配置文件给AccountServiceImpl类里面的方法配置上事务控制,那些方法执行出现异常,就会自动回滚了,也相当于补齐了上面例子中没有写的回滚的功能。

具体怎么整合看下面。

优化后的整合

我们先在spring核心配置文件中加一些配置做到让spring来创建工厂和AccountMapper对象。

做SSM项目的步骤和优化

注意:上面这个工厂类是mybatis-spring包下的,所以我们要把之前注释掉的mybatis和spring整合需要用到的架包给解开。

做SSM项目的步骤和优化

然后我们就可以把mybatis核心配置文件中那些被移到spring核心配置文件中来配置的东西给删了

删除前:

做SSM项目的步骤和优化

删除后:

做SSM项目的步骤和优化

修改AccountServiceImpl。

做SSM项目的步骤和优化

上面是完成了让spring帮我们创建AccountMapper对象。下面我们来把声明式事务控制做了,这样优化后的SSM整合就ok了。

添加事务控制如下:

做SSM项目的步骤和优化

测试:

数据库之前数据:

做SSM项目的步骤和优化

输入:

做SSM项目的步骤和优化

点击保存后:

做SSM项目的步骤和优化

数据库数据:

做SSM项目的步骤和优化

输入http://localhost:8080/ssm_war_exploded/account/findAll,显示的结果如下

做SSM项目的步骤和优化

OK,整合完成,并且测试通过。