Spring-MVC
项目结构
1.配置pom.xml
<?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.mirai</groupId>
<artifactId>springmvc_01_quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.UserController
声明controller定义bean
Controller中进行业务操作
@Controller
public class UserController {
// 设置当前操作的访问路径
@RequestMapping("/save")
// 设置当前操作的返回类型
@ResponseBody
public String save(){
System.out.println("用户保存");
return "{'module':'springmvc'}";
}
}
3.SpringMvcConfig
创建配置文件,加载controller对应的bean
@Configuration
@ComponentScan("com.mirai.controller")
public class SpringMvcConfig {
}
4.ServletInitConfig
定义容器启动的配置类,在其中加载spring的配置
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
过滤器:
简化开发
请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQ6MN8I3-1686798216945)(null)]
GET请求接收参数:
@Controller
public class UserController {
@RequestMapping("/commoParam")
@ResponseBody
//在方法中创造形参接受传递过来的参数
public String commoPrarm(String name,Integer age){
System.out.println(name);
System.out.println(age);
return "{'moudle':'common Param'}";
}
}
POST请求发送表单数据:
POST乱码处理:
在InitConfig中
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
响应不同参数:
//参数不同传参使用@RequestParam('name')
@RequestMapping("/commoParamDiffent")
@ResponseBody
public String commoParamDiffent(@RequestParam("name") String userName, Integer age){
System.out.println(userName);
System.out.println(age);
return "{'moudle':'commoParamDiffent Param'}";
}
接受POJO对象:
//POJO参数
@RequestMapping("/commoParamPOJO")
@ResponseBody
public String commoParamDiffent(User user){
System.out.println(user);
return "{'moudle':'commoParamDiffent Param'}";
}
嵌套POJO参数:
//嵌套POJO参数
@RequestMapping("/commoParamPOJO2")
@ResponseBody
public String commoParamPOJO2(User user){
System.out.println(user);
return "{'moudle':'commoParamPOJO2 Param'}";
}
控制台:User{name='Tom', age=15, address=Address{province='Cn', city='CN'}}
接受数组:
//接受数组
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println(Arrays.toString(likes));
return "{'moudle':'arrayParam arrayParam'}";
}
out:[mousic, q, w, e]
接受集合:
//接受集合
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
likes.forEach(System.out::println);
return "{'moudle':'listParam listParam'}";
}
JSON传参:
1.导入json坐标:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
2.开启json转化为对象【重要】
@EnableWebMvc
3.添加@RequestBody
//json
@RequestMapping("/listParamJSON")
@ResponseBody
public String listParamJSON(@RequestBody List<String> likes){
likes.forEach(System.out::println);
return "{'moudle':'listParam listParam'}";
}
4.发送参数
5.out
aa
bb
cc
JSON POJO传参
1.添加@RequestBody
//JSON POJO参数
@RequestMapping("/JSONParamPOJO")
@ResponseBody
public String JSONParamPOJO(@RequestBody User user){
System.out.println(user);
return "{'moudle':'commoParamDiffent Param'}";
}
2.发送
3.out
User{name='TOM', age=15, address=null}
多个JSON POJO传参
//多个json
@RequestMapping("/JSONlistParam")
@ResponseBody
public String JSONlistParam(@RequestBody List<User> likes){
likes.forEach(System.out::println);
return "{'moudle':'listParam listParam'}";
}
2.send
3.out
User{name='TOM', age=15, address=null}
User{name='TOM666', age=15, address=null}
日期类型传参:
响应
响应/跳转页面:
//跳转路径点
@RequestMapping("/toJumpIndex")
public String toJumpIndex(){
System.out.println("跳转页面");
//跳转页面
return "page.jsp";
}
响应字符串
@RequestMapping("/responseText")
@ResponseBody
public String responseText(){
System.out.println("跳转页面");
return "responseText Text";
}
响应Json对象
@RequestMapping("/JsonResponse")
@ResponseBody
public User JsonResponse(){
System.out.println("跳转页面");
User user = new User();
user.setAge(15);
user.setName("TOm");
return user;
}
响应对各Json对象:
@RequestMapping("/JsonListResponse")
@ResponseBody
public List<User> JsonListResponse(){
System.out.println("跳转页面");
User user = new User();
user.setAge(15);
user.setName("TOm");
User user2 = new User();
user2.setAge(1522);
user2.setName("TOm2222");
List<User> list = new ArrayList<>();
list.add(user);
list.add(user2);
return list;
}
@ResponseBody
REST风格
GET 查询信息
Post 新增/保存
Put 修改/更新
Delete 删除
1.设置请求动作RequestMethod.DELETE
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("user delete..."+id);
return "{'module':'user delete'}";
}
2.设置请求参数value = "/users/{id}"
简化开发:
@RestController
@RequestMapping("/users")
@PostMapping
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public String save(){
System.out.println("user save...");
return "{'module':'user svae'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("user delete..."+id);
return "{'module':'user delete'}";
}
}
案例:
1.放行饭给SPringMVC请求,设置SpringMvcSupport
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
SSM整合
环境: Tomcat7 & spring5
整合流程
![image-20230511210315186](https://i-blog.csdnimg.cn/blog_migrate/bb70e0ad2e35ca9236e58986a0668671.png)
项目结构:
![image-20230511211525124](https://i-blog.csdnimg.cn/blog_migrate/1c97444552c1a9bd8f84b64b9d86823c.png)
1.pom.xml
<?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.itheima</groupId>
<artifactId>springmvc_08_ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.JdbcConfig
package com.mirai.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:29
*/
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String user;
@Value("${jdbc.password}")
private String password;
//链接data
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
//事务管理
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager ds = new DataSourceTransactionManager();
ds.setDataSource(dataSource);
return ds;
}
}
3.jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/student?serverTimezone=Hongkong\
&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=123456
4.MyBatisConfig
package com.mirai.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:29
*/
public class MybatisConfig {
//扫描实体类
@Bean
public SqlSessionFactoryBean sqlSessionFactory (DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.mirai.domain");
return factoryBean;
}
//注入sql语句
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.mirai.dao");
return msc;
}
}
5.ServletConfig
package com.mirai.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:41
*/
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
6.SpringConfig
package com.mirai.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:27
*
*@Configuration 配置类
* @ComponentScan 扫描服务层接口
* @PropertySource 注入jdbc链接
* @Import 引入配置类
* @EnableTransactionManagement 事务管理
*/
@Configuration
@ComponentScan({"com.mirai.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
7.SpringMvcConfig
package com.mirai.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:41
*/
//配置类
@Configuration
//扫描控制层
@ComponentScan("com.mirai.controller")
//
@EnableWebMvc
public class SpringMvcConfig {
}
8.controller 层
负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。
package com.mirai.controller;
import com.mirai.domain.Book;
import com.mirai.service.BookService;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:53
*/
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean save(@RequestBody Book book){
return bookService.save(book);
}
@PutMapping
public boolean update(@RequestBody Book book){
return bookService.update(book);
}
@DeleteMapping("/{id}")
public boolean delete(@PathVariable Integer id){
return bookService.delete(id);
}
@GetMapping("/{id}")
public Book getById(@PathVariable Integer id){
return bookService.getById(id);
}
@GetMapping
public List<Book> getAll(){
return bookService.getAll();
}
}
9.dao层
数据访问层,使用注解开发sql语句
package com.mirai.dao;
import com.mirai.domain.Book;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:53
*/
public interface BookDao {
@Insert("insert into t_book values (null,#{type},#{name},#{description})")
public void save(Book book);
@Update("update t_book set type = #{type},name=#{name},description=#{description} where id= #{id}")
public void update(Book book);
@Delete("delete from t_book where id = #{id}")
public void delete(Integer id);
@Select("select * from t_book where id = #{id}")
public Book getById(Integer id);
@Select("select * from t_book")
public List<Book> getAll();
}
10.service层
dao层的上层,指在完成业务模块的逻辑功能.service接口来进行业务处理,service层的业务层具体要调用已经定义的dao层接口,
BookService
package com.mirai.service;
import com.mirai.domain.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:52
*/
//事务管理
@Transactional
//提供业务层接口
public interface BookService {
//保存图书
public Boolean save(Book book);
//更新图书
public Boolean update(Book book);
//删除图书
public Boolean delete(Integer id);
//根据id搜索图书
public Book getById(Integer id);
//搜索全部
public List<Book> getAll();
}
BookServiceImpl
package com.mirai.service.impl;
import com.mirai.dao.BookDao;
import com.mirai.domain.Book;
import com.mirai.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Mirai
* @version 1.0
* @description: TODO
* @date 2023/5/11 11:51
*/
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public Boolean save(Book book) {
bookDao.save(book);
return true;
}
public Boolean update(Book book) {
bookDao.update(book);
return true;
}
public Boolean delete(Integer id) {
bookDao.delete(id);
return true;
}
public Book getById(Integer id) {
return bookDao.getById(id);
}
public List<Book> getAll() {
return bookDao.getAll();
}
}
三层架构理解
表现层数据封装
Result 类
public class Result {
private Object data;
private Integer code;
private String msg;
code类
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
Controller类中返回值
@PostMapping
public Result save(@RequestBody Book book){
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR, flag);
}
异常处理
异常处理器:
集中统一处理项目中的异常处理
@RestControllerAdvice
public class ProjectExceptoonAdvice {
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
System.out.println("异常处理");
return new Result(666,null,"异常处理");
}
}
项目异常处理:
![image-20230515201845005](https://i-blog.csdnimg.cn/blog_migrate/870cb20d58a995b3d8580d47f6ec9f49.png)
![image-20230515202155310](https://i-blog.csdnimg.cn/blog_migrate/12777836a07c6c9255ebcc5f68e7b952.png)
1.创建异常code:
@Code
public static final Integer SYSTEM_ERR = 59999;
2.创建异常处理器:
package com.mirai.exception;
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public BusinessException( Integer code,String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
3.捕获异常:
@BookServiuceImpl
public Book getById(Integer id) {
if(id < 0){
throw new BusinessException(Code.SYSTEM_ERR,"请输入正确id");
}
return bookDao.getById(id);
}
4.异常处理:
@ProjectExceptionAdvice
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(BusinessException.class)
public Result deBusinessException(BusinessException e){
return new Result(e.getCode(),null,e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
System.out.println("异常处理");
return new Result(666,null,"异常处理");
}
}
解决跨域
新增CorsConfig类
@Configuration
public class CorsConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
在Controller中新增@CrossOrigin
注释
@RestController
@RequestMapping("/books")
@CrossOrigin
public class BookController {}
拦截器
在指定的方法调用前后执行预先的代码
终止原始方法执行
1.新建拦截器类
@Component
public class Projectinterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
2.springmvcSupport中添加
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectinterceptor).addPathPatterns("/books");
}
注解式开发数据库字段和实体类属性不一致问题解决方案
使用@Results
属性id标识当前唯一标识
value中使用@Result
column标识数据库字段名
property标识实体类属性
@Select("select * from t_user where u_name = #{uName} and u_pwd = #{uPwd}")
@Results(id = "groupWithUsers",value = {
@Result(column = "u_id",property = "uid",id = true),
@Result(column = "u_name",property = "uName"),
@Result(column = "u_pwd",property = "uPwd"),
})
public User uLogin(User user);
其他方法中写入@ResultMap
可以重复使用上述Results
@Select("select * from t_user")
@ResultMap(value = {"groupWithUsers"})
public List<User> getAll();