SSM框架整合
文章目录
一、环境搭建
- 新建一个空的Maven项目ssmbulid,在ssmbulid文件夹上右击add framework support选择里面的web,就会在项目中新建一个web文件夹
- 在main->java下新建com.ljh.pojo、dao、service、controller
- 连接数据库
- 配置Tomcat
- 导入依赖
<dependencies>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.14</version>
</dependency>
<!--c3p0-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<!--jstl-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.2</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
注意:一定要在Project Structure中的Artifacts的WEB-INF目录下新建lib目录,然后把所有的Maven包复制进去一份!如果maven依赖变更,也要在lib目录中添加所需依赖!
- 静态资源导出问题
<!--maven配置文件无法被导出或生效-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
二、Mybatis层编写
1、数据库配置文件
resources文件夹下新建db.properties
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false
jdbc.username = root
jdbc.password = 123456
2、Mybatis核心配置文件
resources文件夹下新建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--别名-->
<typeAliases>
<package name="com.ljh.pojo"/>
</typeAliases>
<!--注册mapper-->
<!--<mappers>-->
<!-- <mapper class="com.ljh.dao.StudentMapper"/>-->
<!--</mappers>-->
</configuration>
里面只需要起别名及注册mapper即可。
3、pojo实体类
与数据库表名一一对应
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
private String phone;
}
4、编写dao层
1、编写Mapper接口
public interface StudentMapper {
//添加学生
int addStudent(Student student);
//根据ID删除一个学生
int deleteStudentById(@Param("studentId") int id);
//修改一名学生信息
int updateStudent(Student student);
//根据Id查询学生信息
Student queryStudent(@Param("studentId") int id);
}
2、编写Mapper接口对应的Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ljh.dao.StudentMapper">
<insert id="addStudent" parameterType="Student">
insert into javatest.student values #{id},#{name},#{phone}
</insert>
<delete id="deleteStudentById" parameterType="int">
delete from javatest.student where id = #{studentId}
</delete>
<update id="updateStudent" parameterType="Student">
update javatest.student set name = #{name},phone=#{phone}
where id = #{studentId}
</update>
<select id="queryStudent" parameterType="int" resultType="student">
select * from javatest.student where id =#{studentId}
</select>
</mapper>
注: 一个Mapper.xml
对应一个Mapper接口
,要用namespace
绑定上述接口
一定要在mybatis核心配置文件中注册Mapper
<!--注册mapper-->
<mappers>
<mapper class="com.ljh.dao.StudentMapper"/>
</mappers>
5、编写service层
1、编写service层的接口
public interface StudentService {
//添加学生
int addStudent(Student student);
//根据ID删除一个学生
int deleteStudentById(int id);
//修改一名学生信息
int updateStudent(Student student);
//根据Id查询学生信息
Student queryStudent(int id);
}
2、编写service层接口实现类
service层用来调用dao层,所以内置私有属性为dao层的Mapper接口对象
public class StudentServiceImpl implements StudentService{
//dao层的Mapper接口对象
private StudentMapper studentMapper;
//set方法,为后续Spring注入准备
public void setStudentMapper(StudentMapper studentMapper) {
this.studentMapper = studentMapper;
}
public int addStudent(Student student) {
return studentMapper.addStudent(student);
}
public int deleteStudentById(int id) {
return studentMapper.deleteStudentById(id);
}
public int updateStudent(Student student) {
return studentMapper.updateStudent(student);
}
public Student queryStudent(int id) {
return studentMapper.queryStudent(id);
}
}
三、Spring层编写
1、spring整合dao层
resources文件夹下新建spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--关联数据库配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置c3p0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--引用上述数据源-->
<property name="dataSource" ref="dataSource"/>
<!--绑定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--配置dao接口扫描包,动态实现了Dao接口可以注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--要扫描的dao包-->
<property name="basePackage" value="com.ljh.dao"/>
</bean>
</beans>
2、Spring整合service层
resources文件夹下新建spring-service.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描service下的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.ljh.service"/>
<!--将所有的业务类注入到Spring,可以通过配置或者注解实现-->
<bean id="studentService" class="com.ljh.service.StudentServiceImpl">
<!--这里的ref指向spring-dao.xml最后Spring注入的dao接口-->
<property name="studentMapper" ref="studentMapper"/>
</bean>
<!--声明式事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
四、SpringMVC层编写
1、spring-mvc
resources文件夹下新建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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启SpringMVC注解驱动-->
<mvc:annotation-driven/>
<!--静态资源过滤-->
<mvc:default-servlet-handler/>
<context:component-scan base-package="com.ljh.controller"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
注:在WEB-INF目录下新建jsp文件夹
2、配置文件整合
resources文件夹下新建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
3、配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--DispatcherServlet-->
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--乱码过滤-->
<filter>
<filter-name>encodingFilter</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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--session过期时间-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
4、编写controller层
在controller层中新建StudentController
@Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
@Qualifier("studentService")
private StudentService studentService;
@RequestMapping("/query")
public String query(Model model) {
Student student = studentService.queryStudent(4);
model.addAttribute("stu",student);
return "stu";//指的是/WEB-INF/jsp/stu.jsp
}
}
在jsp文件夹下新建stu.jsp
5、编写jsp
index.jsp
<a href="${pageContext.request.contextPath}/student/query">查询学生</a>
stu.jsp
<body>
${stu}
</body>
启动即可。
五、前后端分离
前端用vue,后端用ssm框架
1、controller层
后端把视图解析器删掉,然后controller层更改代码
@RestController
@CrossOrigin
@RequestMapping("/student")
public class StudentController {
@Autowired
@Qualifier("studentService")
private StudentService studentService;
@RequestMapping("/query")
public String query(@RequestParam("id") int id) {
System.out.println(id);
Student student = studentService.queryStudent(id);
return JSON.toJSONString(student);
}
}
@RestController不会走视图解析器,会直接返回一个字符串
@CrossOrigin解决跨域问题
@RequestParam(“xxx”),其中xxx是前端返回的值,必须和前端的命名相对应
2、Vue
vue用axios接收后端传来的数据
在main.js中导入axios并设定baseURL
import axios from 'axios'
Vue.prototype.$axios = axios;
axios.defaults.baseURL = "http://127.0.0.1:8080";
注意:上面是baseURL不是baseURI,webstorm会智能提示baseURI
编写vue单页面
<template>
<div class="header_wrapper">
<form action="">
<input type="text" placeholder="请输入学号" v-model="code">
<button @click="queryStudentById(code)">查询学生</button>
</form>
<div>{{stu.id}}--{{stu.name}}--{{stu.phone}}</div>
</div>
</template>
<script>
export default {
name: "Header",
data(){
return{
stu:{
id:null,
name:'',
phone:''
},
code:1
}
},
methods:{
queryStudentById(id) {
this.$axios({
url:"/student/query",
method:'post',
params:{
id:id
}
}).then(res=>{
this.stu = res.data;
console.log(res);
}).catch(err=>{
console.log(err);
})
}
}
}
</script>
<style>
.header_wrapper{
margin: 100px auto;
text-align: center;
}
input{
width: 550px;
height: 40px;
margin: 0 auto;
}
</style>
写法一:
this.$axios({
url:“这里是controller层编写的路径”,
method:“get/post”,
params:{
这里写传递给后端的参数
}
}).get(res=>{res.data就是后端传来的数据})
this.$axios.get/post(“url路径”,{
params:{
name:this.name,
phone:this.phone
})
3、axios请求
get请求
- this.$axios.get
- 可以直接在路径后面拼接?id=1
- 添加params(推荐)
post请求
- this.$axios.post
- 引入qs, import qs from ‘qs’ 然后在参数那里用 qs.stringify({id:id})
- 在函数中编写 let params = new URLSearchParams(); params.append(“id”,id); 最后在参数那里写上params
4、添加学生
controller层
@RequestMapping("/add")
public String addStu(@RequestParam("name") String name,@RequestParam("phone") String phone) {
System.out.println(name);
System.out.println(phone);
Map<String,Object> map = new HashMap<String,Object>();
map.put("name",name);
map.put("phone",phone);
int i = studentService.addStudent(map);
if(i>0){
return "成功";
}
return null;
}
注意:controller返回值必须是String
vue单页面
<template>
<div class="content-wrapper">
<form action="" method="get">
name:<input type="text" name="name" v-model="name" placeholder="请输入姓名" required="required">
<br>
phone:<input type="text" name="phone" v-model="phone" required="required">
<input type="submit" value="提交" @click="addStudent($event)">
</form>
</div>
</template>
<script>
export default {
name: "Content",
data() {
return {
name: '',
phone: ''
}
},
mounted() {
},
methods: {
addStudent(e) {
e.preventDefault();
let that = this;
if(this.name&&this.phone) {
this.$axios.get("/student/add",{
params:{
name:this.name,
phone:this.phone
}
}).then(res=>{
console.log(res.data);
if(res.data) {
this.$message({
type: 'success',
message: '添加成功!'
});
}else{
this.$message.error('添加失败!');
}
})
}else{
this.$message({
type: 'warning',
message: '字段不允许为空!'
});
}
}
}
}
</script>
<style scoped>
</style>
4、删除学生
controller
@RequestMapping("/del")
public String deleteStu(@RequestParam("id") int id) {
int i = studentService.deleteStudentById(id);
if(i>0) {
return "删除成功!";
}
return null;
}
vue页面
<template>
<div class="header_wrapper">
<div>
<form action="" method="post">
<input type="text" placeholder="请输入学号" v-model="code">
<button @click="deleteStudentById(code,$event)">删除学生</button>
</form>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data() {
return {}
},
methods: {
deleteStudentById(id,e) {
e.preventDefault();
this.$axios.get("/student/del",{params:{
id:id
}}).then(res=>{
console.log(res.data);
if(res.data) {
this.$message({
type: 'success',
message: '删除成功!'
});
}
}).catch(()=>{
this.$message.error('删除失败!');
})
}
}
}
</script>
<style>
.header_wrapper {
margin: 100px auto;
text-align: center;
}
input {
width: 550px;
height: 40px;
margin: 0 auto;
}
</style>
5、修改学生信息
controller
@RequestMapping("/update")
public String updateStu(@RequestParam("id") int id,@RequestParam("name")String name,@RequestParam("phone")String phone) {
Student student = new Student();
student.setId(id);
student.setName(name);
student.setPhone(phone);
System.out.println(student);
int i = studentService.updateStudent(student);
System.out.println(i);
if(i>0){
return "更新成功!";
}
return null;
}
vue页面
<template>
<div>
<div style="display: flex;margin-left: 20px" v-for="(s,index) in stu">
<input type="text" :value="s.id" disabled><input type="text" ref="getNameValue" :value="s.name"><input type="text" ref="getPhoneValue" :value="s.phone">
<button @click="updateStu(index,s)">修改</button>
</div>
</div>
</template>
<script>
export default{
data(){
return {
stu:[
{
id:'',
name:'',
phone:''
}
]
}
},
components: {
},
methods:{
updateStu(index,stu) {
// console.log(this.$refs.getNameValue[index].value);
// console.log(this.$refs.getPhoneValue[index].value);
stu.name = this.$refs.getNameValue[index].value;
stu.phone = this.$refs.getPhoneValue[index].value;
console.log(stu);
let params = {
id:stu.id,
name:stu.name,
phone:stu.phone
};
console.log(params);
this.$axios.get("/student/update",{params}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
}
},
mounted(){
let that = this;
this.$axios.get("/student/allstu").then(res=>{
// console.log(res);
that.stu = res.data;
}).catch(err=>{
console.log(err);
})
}
}
</script>
注意:SQL语句一定要检查无误,否则排错困难。
六、Vue知识点
1、父子组件传值
- 父组件向子组件传值或函数,子组件获得父组件的数据进行数据渲染
父组件vue
<template>
<div>
<h2>我是父组件</h2>
<div>
<Son :msg="msg"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son"
export default {
name: "Father",
components:{
Son
},
data() {
return{
msg:'slot'
}
},
methods:{
toSon() {
console.log("这里是父组件");
}
}
}
</script>
子组件vue
<template>
<div>父组件传过来的值为:{{msg}}
<button @click="toSon">点我</button>
</div>
</template>
<script>
export default {
name: "Son",
props:{
msg: String,
toSon:Function
}
//也可以是props:['msg']
}
</script>
除此之外,也可以在父组件中的子组件标签添加ref标签<Son ref="getMsg"></Son>
可以在父元素利用this.$refs.getMsg.xxx
取到子组件的值,xxx指的是子组件中data中的数据名
- 子组件数据传给父组件,通过$emit
父组件
<template>
<div>
<h2>我是父组件</h2>
<div>
<Son @getUserName="getName" @getBtnValue="getValue"></Son>
<p>用户名为:{{username}}</p>
<p>按钮值为:{{btnValue}}</p>
</div>
</div>
</template>
<script>
import Son from "./Son"
export default {
name: "Father",
components:{
Son
},
data() {
return{
username:'',
btnValue:''
}
},
methods:{
getName(name) {
this.username = name;
},
getValue(value) {
this.btnValue = value;
}
}
}
</script>
子组件
<template>
<div>我是子组件
<div>
用户名:<input type="text" v-model="name" @change="setName">
<button @click="setBtnValue">子组件传给父组件</button>
</div>
</div>
</template>
<script>
export default {
name: "Son",
data() {
return{
name:'',
btnValue:'我是子组件的数据'
}
},
methods:{
setName() {
this.$emit("getUserName",this.name);
},
setBtnValue() {
this.$emit("getBtnValue",this.btnValue);
}
}
}
</script>
以上面按钮传值为例,子组件传给父组件通过getBtnValue
这个桥梁(在父元素上面定义的@xxx,这里的xxx就是两者的桥梁),在分别在父元素和子元素中各写一个方法,父元素方法写的是具体做的事,子元素的方法就是利用this.$emit
把数据传给父组件。
如果是兄弟组件传值(假设父组件为Father),则利用Father.$emit
和Father.$on
分别作用在两个兄弟组件的方法methods和另一个组件的mounted里面即可。
2、生命周期
-
初始化:
- beforeCreate:一般没啥用,数据没挂载,DOM 没有渲染出来
- created:数据已经挂载,但是 DOM 没有渲染出来,这个钩子函数里面可以做一些异步的操作,并且在这个钩子函数里面更改数据不会影响到运行时钩子函数。
- beforeMounte:这个函数代表着 DOM 快要被渲染出来了,但是还没有被渲染出来,跟 created 一样,做一些异步的操作
- mounted:数据已经挂载,真实 DOM 也已经渲染出来了。
-
运行中:
- beforeUpdate:当数据改变的时候才会执行这个函数,在这个函数里面拿到的是改变之前的数据,千万不能在这个里面更改数据,否则会造成死循环
- updated:拿到的是更新之后的数据,在这函数里面,生成新的 DOM ,跟上一次的虚拟 DOM 做对比,比较出差异之后,然后再渲染真实的 DOM ,当数据引发 DOM 重新渲染的时候,在这个钩子函数里面就可以获取到真实的 DOM。
-
销毁时:
- beforeDestroy:销毁前,做一些善后的操作
- destroyed:数据的双向绑定,监听都删除了,但是真实的 DOM 还是存在的