- 技术栈
说明:前后端分离开发,前端框架Vue+后端框架SSM
1.前端框架Vue
2.后台框架-SSM (SpringMVC+Spring+MyBatis)
3.数据库-MySQL
4.项目的依赖管理-Maven
5.分页-pagehelper
6.逆向工程-MyBatis Generator
7.其它…
1.基础项目环境搭建
1创建项目
目录结构:
<?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>com.codeSE</groupId>
<artifactId>SSM-furn</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SSM-furn Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--引入spring-web 也会引入/导入spring的库/jarl -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
<!-- 引入spring-jdbc,支持事务相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<!--引入spring aspects 切面编程需要的库/jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.8</version>
</dependency>
<!--引入mybatis库/jar-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--引入druid数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!-- 引入mysql驱
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
</project>
配置tomcat,并启动
2项目全局配置web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 1、配置启动Spring容器:
主要配置和业务逻辑有关的,比如数据源,事务控制等-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--
1)、ContextLoaderListener监听器作用是启动Web容器时,自动装配ApplicationContext的配置信息
2)、它实现了ServletContextListener接口,在web.xml配置该监听器,启动容器时,会默认执行它实现的方法
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 2.配置前端控制器/中央控制器/分发控制器
1).用户的请求都会经过它的处理
2).没有指定springmvc的配置文件,那么就会默认按照 servlet-name-servlet.xml来获琅
-->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--在web项目启动时,就自动的加载DispatcherServlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!--
1).这里我们配置的url-pattern是 /,表示用户的请求都经过DispatcherServ
2).这样配置也这次rest风格的url请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--3.配置处理中文乱码的过滤器,全部拦截
-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--4. 配置 HiddenMethodFilter过滤器
1).使用Rest风格的URI,可以把页面发过来的post请求转为指定的delete或者put请求
2).配置url-pattern是/*表示请求都经过hiddenHttpMethodFilter过滤
-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
springmvc配置
1、创建SpringMVC的配置文件dispatcher-servlet.xml:主要包含网站跳转逻辑的控制,一定要在WEB-INF下面
2 、创建相应的包
3、配置扫描com.hspedu包的控制器
4.配置视图解析器
5.加入两个常规配置
6.测试
配置 spring 和mybatis完成整合
1.创建spring的配置文件applicationContext.xml:主要配置和业务逻辑有关的,比如数据源,事务控制等
2.创建D:\lxc\javaProject\SSM-furn\src\main\resources\applicationContext.xml,加入必要的命名空间,提示:同样适用前面的方式创建:右键->New->XML configuration -> SpringConfig
3、配置扫描com.codeSE.furn包,但是不扫描控制器,控制器由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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--
1.扫描com.codeSE.furn包[包括子包]
2.context:exclude-filter配置说明不描控制器
-->
<context:component-scan base-package="com.codeSE.furn">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
4、创建jdbc.properties,配置链接数据库的信息
jdbc.Driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/xxx?useSSL=true&&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
5、配置数据源配置mybatis-config.xml
6、配置spring和mybatis整合
7、在类路径resources下创建D:\lxc\javaProject\SSM-furn\src\main\resources\mybatis-config.xml
8、在resources类路径下创建mapper目录,存放mapper的xml文件
9、配置将mybatis接口实现加入到ioc容器,在applicationContext.xml配置
<!--配置扫描器,将mybatis接口的实现加入到Toc容器中
1、我们的mapper接口放在com.codeSE.furn.dao
2. mybatis就是处于DAO层,操作DB
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--
1.扫描所有的dao接口的实现,加入到ioc容器中
2.这里dao接口,就是mapper接口
-->
<property name="basePackage" value="com.codeSE.furn.dao"/>
</bean>
10、配置事务控制,在applicationContext.xml配置
11、配置开启基于注解的事务,并指定切入点.applicationContext.xml配置
<!--
解读:
1.开启基于注解的事务,并指定切入点
2.execution(* com.codeSE.furn.service..*(..)):
表示对com.codeSE.furn.service包所有类的所有方法控制事务3. tx:advice :配置事务增强,也就是指定事务如何切入
3. tx:advice : 配置事务增强,也就是指定事务如何切入
4.不需要背,但是能看到,能修改,能维升
-->
<aop:config>
<!--表达式切入点-->
<aop:pointcut id="txPoint" expression="execution(* com.codeSE.furn.service..*(..))"/>
<!--配置事务增强/规则:使用txAdvice指定规则对txPoint进行切入-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!--配置事务增强【指定事务规则】,也就是指定事务如何切入-->
<tx:advice id="txAdvice">
<tx:attributes>
<!--*代表所有方法都是事务方法-->
<tx:method name="*"/>
<!--get开始的所有方法,我们认为是只读,进行调优-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
12.测试,D:\lxc\javaProject\SSM-furn\src\test\java\com\codeSE\furn\test\T1.java
创建表,使用逆向工程生成Bean、XxxMapper和XxxMapper.xml
创建表,便用逆向工程生成Bean、XxxMapper和XxxMapper.xml
1.创建furns_ssm 数据库和furns表
-- 创建furns _ssm
DROP DATABASE IF EXISTS furns_ssm;
CREATE DATABASE furns_ssm;
USE furns_ssm;
-- 创建家居表
CREATE TABLE furn (
`id`INT(11)PRIMARY KEY auto_increment, ## id
`name` VARCHAR(64) NOT NULL, ## 家居名
`maker` VARCHAR (64) NOT NULL, ##厂商
`price` DECIMAL(11,2) NOT NULL, ##价格
`sales` INT(11) NOT NULL,## 销最
`stock`INT(11) NOT NULL,##库存
`img path` VARCHAR (256) NOT NULL##照片路径
);
-- 添加一些数据进去
2.使用MyBatis Generator逆向工程生成bean mapper接口和mapper.xml,当然也可以自己写
1)修改mybatis-config.xml,增加typeAliases配置.
2)引入MyBatis Generator包,在pom.xml配置
3)在项目根目录下新建bmg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--生成没有注释的bean-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--配置数据库连接信息-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/furns_ssm?characterEncoding=UTF-8"
userId="root"
password="123456">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--指定javaBean生成的位置-->
<javaModelGenerator targetPackage="com.codeSE.furn.bean" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--指定sql映射文件生成的位置-->
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 指定dao接口生成的位置,也就是mapper接口-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.codeSE.furn.dao" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--指定要逆向生成的表和生成策略s-->
<table tableName="furn" domainObjectName="Furn"/>
</context>
</generatorConfiguration>
4)新建生成相关bean, mapper接口和mapper.xml参考官方问题来修改,并完成测试,查看生成的文件
package com.codeSE.furn.test;
import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MBGTest {
@Test
public void generator() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//这里要指定你自己配置的mbg.xml
//如果这样访问,需要将文件放在项目下
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("逆行生成OK了,在对应文件查看");
}
}
3.使用Junit测试Spring和MyBatis是否整合成功,能通过MyBatis添加furn到数据库
ppackage com.codeSE.furn.test;
import com.codeSE.furn.bean.Furn;
import com.codeSE.furn.dao.FurnMapper;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.math.BigDecimal;
public class FurnMapperTest {
@Test
public void insertSelective() {
//1.获取到容聪
ApplicationContext ioc =
new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取Bean
FurnMapper furnMapper = ioc.getBean(FurnMapper.class);
//System.out.println(furnMapper);
Furn furn = new Furn(null, "超酷电竞椅","我的家居", new BigDecimal("299.89"), 123, 300, "assets/images/product-image/100.jpg");
int i = furnMapper.insertSelective(furn);
System.out.println("执行成功:"+i);
}
@Test
public void deleteByPrimaryKey(){
ApplicationContext ioc =
new ClassPathXmlApplicationContext("applicationContext.xml");
FurnMapper furnMapper = ioc.getBean(FurnMapper.class);
int i = furnMapper.deleteByPrimaryKey(14);
System.out.println("执行成功:"+i);
}
@Test
public void updateByPrimaryKey(){
ApplicationContext ioc =
new ClassPathXmlApplicationContext("applicationContext.xml");
FurnMapper furnMapper = ioc.getBean(FurnMapper.class);
Furn furn = new Furn();
furn.setId(16);
furn.setName("上世纪家居");
//会修改所有的字段,如果没有设置字段对应的属性值,那么默认是null
//int i = furnMapper.updateByPrimaryKey(furn);
int i = furnMapper.updateByPrimaryKeySelective(furn);
System.out.println("执行成功:"+i);
}
@Test
public void selectByPrimaryKey(){
ApplicationContext ioc =
new ClassPathXmlApplicationContext("applicationContext.xml");
FurnMapper furnMapper = ioc.getBean(FurnMapper.class);
Furn furn = furnMapper.selectByPrimaryKey(20);
System.out.println("执行成功:"+furn);
}
}
注意事项和细节说明
1、insertSelective和insert的区别
- insertSelective——选择性保存数据;
比如User里面有三个字段:id,name,age,password但是只设置了一个字段;
User u=new user();u.setName(“张三”);insertSelective(u); - insertSelective执行对应的sql语句的时候,只插入对应的name字段;(主键是自动添加的,默认插入为空)insert into tb__user (id,name) value (null,“张三”) ﹔
3)而insert则是不论设置多少个字段,统一都要添加一遍,不论你设置几个字段,即使是
User u=new user();
u.setName(“张三”);
搭建vue3前端工程
这部分省略,简单提一下:
1.先下载较高版本node.js LTS并安装: node.js 的npm,用于管理前端项目包依赖,方便我们使用vue3
1)node.js安装非常简单,直接下一步即可
2)验证node.js是否安装成功
3)全局安装Vue插件cli : npm install -g @vue/cli,这样我们就可以创建Vue工程
2.创建Vue项目–因为我们是前后端分离,所以新建一个前端项目,指令vue create ssm-vue
3.启动项目,安装依赖,如element-plus vue-router 等等
1.实现添加的功能
1)完成后台代码从dao -> serivce -> controller,并对每层代码进行测试,到controller这一层,使用Postman发送http post请求完成测试
2)完成前端代码,使用axios '发送json数据给后台,实现添加家居信息
写service和servicelmp
package com.codeSE.furn.service;
import com.codeSE.furn.bean.Furn;
public interface FurnService {
void save(Furn furn);
}
package com.codeSE.furn.service.impl;
import com.codeSE.furn.bean.Furn;
import com.codeSE.furn.dao.FurnMapper;
import com.codeSE.furn.service.FurnService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class FurnServiceImpl implements FurnService {
//注入/装配FurnMapper接口对象(代理对象)
@Resource
private FurnMapper furnMapper;
@Override
public void save(Furn furn) {
furnMapper.insertSelective(furn);
}
}
测试一把,看是否添加成功
package com.codeSE.furn.service;
import com.codeSE.furn.bean.Furn;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.math.BigDecimal;
public class FurnServiceTest {
private ApplicationContext ioc;
//从spring容器中,获取的是FurnService接口对象/代理对象
private FurnService furnService;
@Before
public void init() {
ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
furnService = ioc.getBean(FurnService.class);
//System.out.println("furnService==="+furnService);
}
@Test
public void save() {
Furn furn = new Furn(null, "超酷电竞椅22", "中国家居22", new BigDecimal("2299.89"), 1223, 44, "assets/images/product-image/100.jpg");
furnService.save(furn);
System.out.println("添加成功");
}
}
返回json数据通用message封装
package com.codeSE.furn.bean;
import java.util.HashMap;
import java.util.Map;
/*
* Msg:后端程序返回给前端的json数据的Msg对象==>本质就是数据规则
*
* */
public class Msg {
private int code;
private String msg;
private Map<String,Object> extend = new HashMap<>();
public static Msg success(){
Msg msg = new Msg();
msg.setCode(200);
msg.setMsg("success");
return msg;
}
public static Msg fail(){
Msg msg = new Msg();
msg.setCode(400);
msg.setMsg("fail");
return msg;
}
public Msg add(String key,Object data){
extend.put(key,data);
return this;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Map<String, Object> getData() {
return extend;
}
public void setData(Map<String, Object> extend) {
this.extend = extend;
}
}
4.创建FurnController.java,处理添加请求
package com.codeSE.furn.controller;
import com.codeSE.furn.bean.Furn;
import com.codeSE.furn.bean.Msg;
import com.codeSE.furn.service.FurnService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
@RequestMapping("/furn")
public class FurnController {
//注入配置FurnService
@Resource
private FurnService furnService;
@PostMapping("/save")
@ResponseBody
public Msg save(@RequestBody Furn furn) {
System.out.println("请求进来le----");
System.out.println(furn);
furnService.save(furn);
//返回成功信息
Msg success = Msg.success();
return success;
}
}
5.postman发接口测试
6.在前端页面发接口
注意事项
:
1)Postman测试时,要指定content-type,否则会报错415
2)如果需要将提交的json数据,封装到对应的Javabean,需要配置@RequestBody,否则会报错500
3)如需要返回json数据,需要在方法上,配置@ResponseBody,否则会报错40
2.实现显示数据列表的功能
思路分析:
1.完成后台代码从dao ->serivce -> controller,并对每层代码进行测试
2.完成前台代码,使用axios 发送 http请求,返回所有家居数据,将数据绑定显示
service层:
controlle层:
3.修改家居信息功能
简单略
4.删除家居信息功能
简单略
5.改进返回列表(分页展示)
- 引入分页插件
<!--引入mybatis pageHelper分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.1</version>
</dependency>
- 修改mybatis-config.xml,配置分页拦截器
<!--说明
1. plugins标签需要放在typeAliases标签后,是doctype约束的
2.配置分页拦截器
-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--分页合理化,如果pageNum > pages,就让他查询最后一页。如果pageNum<0,就查询第一页-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
- 修改FurnController.java增加分页查询处理
@GetMapping("/furnByPage")
@ResponseBody
public Msg furnByPage(@RequestParam(defaultValue = "1") Integer pageNo,
@RequestParam(defaultValue = "10") Integer pageSize) {
//设置分页参数老师解读
//1.调用findAll是完成查询,底层会进行物理分页,而不是逻辑分页
// 2.会根据分页参数来计算limit ?,?,在发出SQL语句时,会带limit
PageHelper.startPage(pageNo, pageSize);
List<Furn> furnList = furnService.findAll();
//将分页查询的结果,封装到PageInfo
// PageInfo对象包含了分页的各个信息,比如当前页面pageNum ,共有多少记录
PageInfo<Furn> furnPageInfo = new PageInfo<>(furnList, pageSize);
return Msg.success().add("items", furnPageInfo);
}
6.改进返回列表带条件搜索(分页展示)
impl:
@Override
public List<Furn> findByConditionPage(String name) {
FurnExample furnExample = new FurnExample();
///通过Criteria 对象可以设置查询条件
FurnExample.Criteria criteria = furnExample.createCriteria();
if(StringUtils.hasText(name)){
criteria.andNameLike("%"+name+"%");
}
return furnMapper.selectByExample(furnExample);
}
controller:
@GetMapping("/furnByConditionPage")
@ResponseBody
public Msg furnByConditionPage(@RequestParam(defaultValue = "1") Integer pageNo,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String name) {
//设置分页参数老师解读
//1.调用findAll是完成查询,底层会进行物理分页,而不是逻辑分页
// 2.会根据分页参数来计算limit ?,?,在发出SQL语句时,会带limit
PageHelper.startPage(pageNo, pageSize);
List<Furn> furnList = furnService.findByConditionPage(name);
//将分页查询的结果,封装到PageInfo
// PageInfo对象包含了分页的各个信息,比如当前页面pageNum ,共有多少记录
PageInfo<Furn> furnPageInfo = new PageInfo<>(furnList, pageSize);
return Msg.success().add("items", furnPageInfo);
}
后端数据校验
1.修改pom.xml引入hibernate-validator.jar文件
2.