# SSM **Repository Path**: springff/SSM ## Basic Information - **Project Name**: SSM - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-15 - **Last Updated**: 2021-06-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SSM框架学习(参考:我没有三颗心脏博客) ## 参考: [MyBatis 与 Spring 整合](https://www.cnblogs.com/wmyskxz/p/8879513.html) [IDEA 整合 SSM 框架学习](https://www.cnblogs.com/wmyskxz/p/8916365.html) [学生管理系统(SSM简易版)总结](https://www.cnblogs.com/wmyskxz/p/8933898.html) ## 学习内容: - Mybatis Spring 框架整合 - IDEA 整合 SSM 框架学习 - 学生管理系统(SSM简易版 ## Mybatis Spring 框架整合 ### 实现步骤: - 创建Maven Spring Web 项目,导入Mybatis框架,创建对应的包 - 创建对应的配置文件: applicationContext.xml, sqlMapConfig.xml ; db.properties, log4j.properties - 实体类,dao层,mapper层编写,StudentMapper.xml ,测试类编写 感觉比较复杂的就是配置文件的具体配置 #### 工程目录: ![image-20210315202859520](readme.assets/image-20210315202859520.png) #### 添加依赖: ```xml org.springframework spring-context 5.3.3 org.springframework spring-jdbc 5.3.3 org.springframework spring-tx 5.3.3 org.mybatis mybatis 3.4.6 mysql mysql-connector-java 5.1.49 org.mybatis mybatis-spring 1.3.2 junit junit 4.11 test ``` #### 配置文件: applicationContext.xml, sqlMapConfig.xml ; db.properties ```xml ``` ```xml ``` #### 相关代码: 实体类,dao层,mapper层编写,StudentMapper.xml ,测试类编写 ```java package org.ff.pojo; public class Student { private int id; private String name; private int card_id; /* getter and setter */ } ``` ```java package org.ff.dao; import org.ff.pojo.Student; public interface StudentDao { public Student findStudentById(int id) throws Exception; } ``` ```java package org.ff.dao; import org.apache.ibatis.session.SqlSession; import org.ff.pojo.Student; import org.mybatis.spring.support.SqlSessionDaoSupport; public class StudentDAOImpl extends SqlSessionDaoSupport implements StudentDao{ @Override public Student findStudentById(int id) throws Exception { SqlSession sqlSession = this.getSqlSession(); Student student = sqlSession.selectOne("student.findStudentById", id); return student; } } ``` ```xml ``` ```java package org.ff.mapper; import org.ff.dao.StudentDao; import org.ff.pojo.Student; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MybatisTest { private ApplicationContext context; @Before public void setup(){ context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); } @Test public void findStudentByIdTest(){ StudentDao studentDao = (StudentDao) context.getBean("studentDao"); Student stu = null; try { stu = studentDao.findStudentById(1); } catch (Exception e) { e.printStackTrace(); } System.out.println(stu); } } ``` - @Before注解表示在调用@Test方法之前会自动调用添加注解的方法 ### 动态代理+注解的方式实现 - 创建StudentQueryMapper.java代理接口, - 配置Mapper扫描器MapperScannerConfigurer(不用手动配置在SqlMapperConfig.xml中配置mapper了吗) - 拿到mapper执行调用代理接口方法 #### 相关代码: StudentQueryMapper.java,applicationContext.xml添加Mapper扫描,SqlMapperConfig.xml删除关于Mappers引用的配置,测试 ```java package org.ff.mapper; import org.apache.ibatis.annotations.Select; import org.ff.pojo.Student; public interface StudentMapper { @Select("SELECT * FROM student WHERE id = #{id}") Student findStudentById(int id); } ``` ```xml ``` ```xml ``` ```java @Test public void findStudentWithIdTest(){ StudentMapper studentMapper = (StudentMapper) context.getBean("studentMapper"); Student student = studentMapper.findStudentById(1); System.out.println(student); } ``` #### 注意: ​ 当StudentMapper.xml(包含sql语句的mapp),和StudentMapper(动态代理和注解方式)在同一包中时,通过设置Mapper扫描包为当前包,会报错 ![image-20210315235510326](readme.assets/image-20210315235510326.png) ![image-20210315235521161](readme.assets/image-20210315235521161.png) ​ 删除StudentMapper.xml就不会报错了,命名空间冲突吗,动态代理+注解和xml配置方式只能选一种吗?或者新建一个设置动态代理扫描的包,使用动态代理+注解的mapper代理接口都放到这个专门的包中。 ### 总结: - mapper.xml中的 namespace 表示的本条sql语句所属的命名空间,设置之后通过sqlSession或者Mapper映射类调用sql的时候都可以用 【namespace. sql语句id】 的形式指明调用的是那一条sql。 - spring mybatis 整合一句话总结:spring将mybatis中获取SqlSessionFactory, SqlSession对象的进行di(依赖注入),不需要手动实例化这两个对象。 - spring mybatis 调用流程 ![image-20210315164217089](readme.assets/image-20210315164217089.png) ## IDEA 整合 SSM 框架学习 ### 实现步骤: - 创建数据库 - 构建Maven javaweb 项目,创建对应的资源目录 - Maven添加相关依赖,配置基础的配置文件web.xml, spring核心配置,mybatis核心配置,jdbc.properties, logback.xml - 实体类,Dao接口,映射sql.xml - 测试spring-mybatis(使用spring自带的JUnit)(这步省略也没事) - Service接口,Service接口实现类,UserControlle类,jsp - 运行到服务器tomcat,测试 #### 创建数据库: ```sql DROP DATABASE IF EXISTS ssm; CREATE DATABASE ssm CHARACTER SET utf8; USE ssm; CREATE TABLE `user`( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO `user` VALUES(1,'阿凡达'); SELECT * FROM `user`; ``` #### 添加依赖,*.xml配置文件: pom.xml, web.xml, spring-mybatis.xml, spring-mvc.xml, jdbc.propertis ```xml 4.0.0 org.example SSM02 1.0-SNAPSHOT war SSM02 Maven Webapp http://www.example.com UTF-8 1.8 1.8 5.3.3 3.4.6 org.springframework spring-core ${spring.version} org.springframework spring-beans ${spring.version} org.springframework spring-context ${spring.version} org.springframework spring-jdbc ${spring.version} org.springframework spring-tx ${spring.version} org.springframework spring-web ${spring.version} org.springframework spring-webmvc ${spring.version} org.springframework spring-test ${spring.version} mysql mysql-connector-java 5.1.49 com.mchange c3p0 0.9.5.2 org.mybatis mybatis ${mybatis.version} org.mybatis mybatis-spring 1.3.2 junit junit 4.12 test javax.servlet jstl 1.2 SSM02 ``` ```xml Archetype Created Web Application encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 encodingFilter /* SpringMVC org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-*.xml 1 true SpringMVC / ``` ```xml ``` ```xml ``` ```properties #jdbc.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost/ssm?useSSL=false jdbc.username=root jdbc.password=root123 #最大连接数 c3p0.maxPoolSize=30 #最小连接数 c3p0.minPoolSize=10 #关闭连接后不自动commit c3p0.autoCommitOnClose=false #设置连接超时时间 c3p0.checkoutTimeout=10000 #连接超时之后重试的次数 c3p0.acquireRetryAttempts=2 ``` - pom.xml 用于添加spring,mytatis,springmvc相关模块的依赖,其中spring-core, spring-beans感觉都不需要添加,spring-test是用来测试spring+mybatis数据连接的 - web.xml Web项目启动初始化的一个配置文件,配置编码过滤器,DispathcerServlet(配置contextConfigLoacation,在初始化的时候去初始化spring,mybatis框架) - spring-mybatis.xml :注册自动扫描的包,创建带数据库连接池的DataSource,创建SqlSessionFactory(关键部分是配置*mapper.xml的扫描),配置动态代理的扫描(用于Dao接口的DI),配置事务管理 - spring-mvc.xml:Controller包的DI扫描,设置注解模式, 静态资源的加载,开启jsp访问保护 #### 相关代码: User.java, UserDao.java, UserDao.xml, UserDaoTest.java, UserService.java, UserServiceImpl, UserController.java, index.jsp ```java package org.ff.entity; public class User { private int id; private String username; /* getter and setter */ } ``` ```java package org.ff.dao; import org.ff.entity.User; public interface UserDao { User findUserById(int id); } ``` ```xml ``` ```java package org.ff.dao; import org.ff.entity.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:spring-mybatis.xml"}) //@ContextConfiguration() 表示自动加载spring核心配置文件,不需要ClassPathXMLApplicationContext根据核心配置文件去拿到上下文 public class UserDaoTest { @Autowired // @Autowired 自动装载 private UserDao userDao; @Test public void testFindUserById(){ //spring-mybatis中值配置了扫描service包,userDao能够别自动装载吗?居然真的可以找找到,神奇 //注释了整条 component-scan 发现仍然能够DI成功 //spring-mybatis.xml中配置的 MapperScannerConfigurer配置了扫描动态代理的dao包 int id = 1; User user = userDao.findUserById(id); System.out.println(user); } } ``` ```java package org.ff.service; import org.ff.entity.User; public interface UserService { User findUserById(int id); } ``` ```java package org.ff.service; import org.ff.dao.UserDao; import org.ff.entity.User; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service("userService") public class UserServiceImpl implements UserService{ @Resource //@Resource 也是自动装载的意思吗? private UserDao userDao; @Override public User findUserById(int id) { return userDao.findUserById(id); } } ``` ```java package org.ff.controller; import org.ff.entity.User; import org.ff.service.UserService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.annotation.Resource; @Controller @RequestMapping("") //在类定义的外部注解@RequestMapping的作用? public class UserController { @Resource private UserService userService; @RequestMapping("/findUser") public String findUser(Model model){ int id = 1; User user = userService.findUserById(id); model.addAttribute("user",user); return "index"; } } ``` ```jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored="false" %> SSM框架整合 in

Hello ${user.id}:${user.username}

``` #### 问题: **实体类别名的使用有问题,需要使用完全限定名** ![image-20210317104347297](readme.assets/image-20210317104347297.png) ![image-20210317104524415](readme.assets/image-20210317104524415.png) ​ 即使在spring-mybatis.xml--sqlSessionFactory的配置中添加了别名,在编写*Mapper.xml的时候还是需要使用完全限定名(不对); ​ 发现在sqlSessionFactory的配置中,包的路径value="org.fff".entity写错了 **jsp页面没有解析(其实是EL表达式没有生效)** ​ 估计和javaee包的导入不成功有关系,百度说是jar冲突,tomcat也有自带的相关jar包,尝试删除tomcat包下得jar引用,卡在这里了 ![image-20210316141206807](readme.assets/image-20210316141206807.png) - 删除tomcat下的jar包: servlet-api.jar(很遗憾没有用) ![image-20210316142549624](readme.assets/image-20210316142549624.png) ​ 解决方案:弄了一下午,其实是el表达式没有生效导致,javaee导入不成功是会报错,设置不忽略EL表达式就可以 ```xml <%@ page isELIgnored="false" %> ``` **spring-mvc.xml中添加jsp隐藏 InternalResourceViewResolver 报错:**java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config ​ 解决方案:pom.xml中添加【jstl】的依赖 ```xml javax.servlet jstl 1.2 ``` ### 总结: - mybatis动态代理可以结合 Mapper.xml文件,也可以结合注解使用 - Idea框架整合SSM复杂的地方是配置文件的添加,spring-batis.xml 整合了spring以及mybatis的核心配置文件,与单个的去配合有些许不一致,整体的关键字就是:DataSource, SqlSessionFactory, 动态代理Mapper的DI,spring-mvc.xml和单个的SpringMVC的demo一样 - SSM框架使用的优势: - 在不集成SpringMVC的前提下就可以完成Model层的单元测试,不需要将整个Web工程运行后测试 - 创建service接口及其实现类,可以完成添加上业务逻辑,单个service接口的实例可以拥有多个Dao的实例 - SSM框架相较于Spring Mybatis框架整合,没有单独添加mybatis的配置文件,直接SqlSessionFactory中扫描)*mapper.xml ## 学生管理系统(SSM简易版) ### 目标: - 学生信息管理系统在SSM框架的基础上完成对学生信息的crud,添加了页面 - 加深对SSM框架的理解,回顾前端开发的知识点 ### 思路: - 需求比较简单,将功能点列出来,数据表的操作,页面之间的跳转 - 数据表的创建,sql语句的编写,框架的搭建,dao层的访问测试,controller带数据跳转测试(测试跳转之前写个简单jsp页面) - 静态页面完成,前后端联调 ### 实现步骤: - 创建数据库,数据表 - 创建工程,添加依赖,配置web.xml, spring-mybatis.xml - 页面逻辑分析 - 实体类,dao接口,service接口,service实现类,controller控制 - #### 数据库创建 ```sql DROP DATABASE IF EXISTS `student`; CREATE DATABASE `student` DEFAULT CHARACTER SET UTF8; USE student; DROP TABLE IF EXISTS `student`; 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 CHARACTER SET = utf8; USE student; INSERT INTO student VALUES(null,1111,'阿凡达',15,'男','1997-01-01'); ``` #### 配置文件添加 ```xml ``` ```xml ``` ```xml ``` ```xml ``` #### 页面逻辑分析 home.jsp 首页:包括学生展示,和新增模块 - 展示所有学生信息,可以直接用table展示就行, - 点击编辑直接跳转到编辑页面, - 点击删除直接删除,重新加载本页面 - 新增模块直接copy新增页面的代码,新增成功之后重新加载本页面 edit.jsp页面: - form表单展示,提交成功之后跳转回首页,提交不成功也需要有提示 #### 相关代码 Student.java, StudentDao.java, StudentDap.xml, StudentService.java, StudentServiceImpl.java, #### 静态页面 静态页面至少写了30分钟,这么简单的页面,写了这么久,不应该 #### Controller页面控制,*.jsp修改联调 - 展示所有学生 - 编辑页面数据显示 - 编辑提交处理 - 新增提交之后,刷新列表页面 ### 第二版修改 controller中mapping的参数和返回值可以是多种形式 jsp页面优化,日期展示优化 加上分页的代码 分页的逻辑卸载controller中还是写在service中的,应该是service中,并没有,是在cotroller中 - sql语句分页查询,可以通过传入起始页和每页的数据数,完全通过拿到对应的数据 - 前台需要展示总共有多少页,当前在那一页 - sql只负责从那一条数据开始查,查多少条,页数的维护交给java - 照着实现一遍 ### 问题: **StudentDaoTest新增的中文数据在数据库中是乱码的** ​ 是因为数据库连接字符串需要设置unicode编码和utf-8编码 ```properties jdbc.url=jdbc:mysql://localhost:3306/student?useSSL=false&useUnicode=true&characterEncoding=UTF-8 ``` **student表中的学号不应该是int** ​ 主键id为[id]字段,student_id只是用来记录学生的学号,学号包含了入学信息、班级信息,比较长,并且学号并不会用来计算,应该使用varchar数据类型 **发布的web项目静态文件在jsp生成的网页中仍然无法找到** ​ spring-mvc.xml中配置静态资源加载模式 ```xml ``` ​ 将静态资源直接放到webapp目录下,不需要加上二级目录 ![image-20210320094007601](readme.assets/image-20210320094007601.png) **jsp页面使用el表达式获取不到controller层绑定的属性** ​ 在jsp页面通过request.getParameter()获取不到Contrlloer放在ModelAndView中的值;尝试用jstl标签库试一下 ​ 解决方案:使用el表达式 + jstl 标签可以获取到传递的对象 ​ 参考:[jsp,el表达式,foreach循环](https://blog.csdn.net/JacaCao/article/details/107127227) **Controller中获取GET/POST请求传递的参数** ​ 方式一:直接在方法的参数列表中写上参数的名称,参数名称需要和url中所带参数名一致,例如:url : http://localhost:8888/deleteStudent?id=1 ```java @RequestMapping("/deleteStudent") public String deleteStudent(int id){ studentService.deleteStudent(id); return "redirect:/listStudent"; } ``` 补充:当url中的参数名和mapping方法的参数名不一致时,可以采用@RequestParam注解进行转换 ```java @RequestMapping("/editStudent") public String editStudent(Model model, @RequestParam("id") Integer id){ //根据id查找学生信息,填充显示 Student student = studentService.getStudent(id); model.addAttribute("student",student); return "editStudent"; } ``` ​ 方式二:在方法的参数列表中添加上 HTTPServletRequest request 参数,直接通过request对象获取传递的参数 ```java @RequestMapping("/addStudent") public String addStudent(HttpServletRequest request){ //输入参数可以是request,response;也可以是前端传递的参数名;也可以是值对应的实体类对象 int student_id = Integer.parseInt(request.getParameter("student_id")); String name = request.getParameter("name"); /*省略获取其他参数*/ return "redirect:/listStudent"; } ``` ​ 方式三:当进行表单提交的时,表单内容和实体类对应,可以直接使用实体类作为方法的参数声明 ```java @RequestMapping("/addStudent") public String addStudent(Student student){ studentService.addStudent(student); return "redirect:/listStudent"; } ``` 补充: ​ 当实体类中存在Date类型的属性时,只有特定格式的字符串【Web Mar 17 00:00:00 CTS 2021】能够自动转换为Date,但是例如【2021-01-01】这种格式的字符串是无法进行转换的,这时提交数据会报400错误,数据转换导致的报错。 ​ 遇到此类情况,可以采用request对象获取数据,然后使用SimpleDateFormat进行数据类型转换。 **参考:**[springmvc的controller中如何接收前台传来的参数](https://blog.csdn.net/lycyl/article/details/89336020) **controller中相互调用url相互跳转** ​ controller中添加了多个@RequestMapping,如何在MappingA逻辑处理完成之后跳转到MappingB的映射url请求中? ​ 使用 request/forward:/url的形式进行跳转 ```java @RequestMapping("/deleteStudent") public String deleteStudent(int id){ studentService.deleteStudent(id); return "redirect:/listStudent"; } ``` ​ 参考:[Controller 之间的跳转](https://www.cnblogs.com/renxiuxing/p/12747097.html) **新增记录时生日这个值的格式问题导致更新失败** ​ 调用新增的时错误码:400(此时参数接收采用的是自动转换为Student对象的接收形式) ![image-20210317200019415](readme.assets/image-20210317200019415.png) ​ 是date和datetime的问题,还是日期格式的问题?原因是sql插入失败,返回受影响行数0 ​ 发现是日期格式错误导致,直接复制列表中的日期【Web Mar 17 00:00:00 CTS 2021】去新增就不报错 **新增数据中文乱码** ​ 存放到数据库中的数据乱码,通过断点调试发现,到Controller层的数据都是正常的,在Spring Mybatis测试类中直接插入中文也是乱码,[解决插入到数据库出现的中文乱码问题](https://blog.csdn.net/weixin_44538032/article/details/90245035) 和这篇文章描述的一样,数据库的编码也是设置的utf8;问题发现是,数据库连接没有指定编码格式,需要加上useUnicode,character属性。 ``` jdbc.url=jdbc:mysql://localhost:3306/student?useSSL=false&useUnicode=true&characterEncoding=UTF-8 ``` ​ 参考:[接口400错误解析](https://blog.csdn.net/lw1242189467/article/details/80048407)