# 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 ,测试类编写
感觉比较复杂的就是配置文件的具体配置
#### 工程目录:

#### 添加依赖:
```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扫描包为当前包,会报错


删除StudentMapper.xml就不会报错了,命名空间冲突吗,动态代理+注解和xml配置方式只能选一种吗?或者新建一个设置动态代理扫描的包,使用动态代理+注解的mapper代理接口都放到这个专门的包中。
### 总结:
- mapper.xml中的 namespace 表示的本条sql语句所属的命名空间,设置之后通过sqlSession或者Mapper映射类调用sql的时候都可以用 【namespace. sql语句id】 的形式指明调用的是那一条sql。
- spring mybatis 整合一句话总结:spring将mybatis中获取SqlSessionFactory, SqlSession对象的进行di(依赖注入),不需要手动实例化这两个对象。
- spring mybatis 调用流程

## 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}
```
#### 问题:
**实体类别名的使用有问题,需要使用完全限定名**


即使在spring-mybatis.xml--sqlSessionFactory的配置中添加了别名,在编写*Mapper.xml的时候还是需要使用完全限定名(不对);
发现在sqlSessionFactory的配置中,包的路径value="org.fff".entity写错了
**jsp页面没有解析(其实是EL表达式没有生效)**
估计和javaee包的导入不成功有关系,百度说是jar冲突,tomcat也有自带的相关jar包,尝试删除tomcat包下得jar引用,卡在这里了

- 删除tomcat下的jar包: servlet-api.jar(很遗憾没有用)

解决方案:弄了一下午,其实是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目录下,不需要加上二级目录

**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对象的接收形式)

是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)