SpringMVC基础知识

SpringMVC

SpringMVC简介

SpringMVC是一种基于Java实现MVC模型的轻量级web框架

优点

使用简单,开发便捷

灵活性强

入门案例

1、创建web工程(maven结构)

2、设置tomcat服务器,加载web工程(tomcat插件)

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

3、导入坐标(SpringMVC+Servlet)

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

4、定义处理请求的功能类(UserController)

@Controller public class UesrController { public String save(){ System.out.println("user save ..."); return "{'info':'springMVC'}"; } }

5、设置请求映射(配置映射关系)

为UserController添加注解

@Controller public class UesrController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save ..."); return "{'info':'springMVC'}"; } }

6、将SpringMVC设定加载到tomcat服务器

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { //加载SpringMVC对应的容器对象 protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } protected String[] getServletMappings() {return new String[]{"/"};} //加载Spring配置对应的容器对象 protected WebApplicationContext createRootApplicationContext() {return null;} }

入门案例工作流程分析

启动服务器初始化过程

1、服务器启动,执行ServletContainersInitConfig类,初始化web容器

2、执行createServletApplicationContext方法,创建WebApplicationContext对象

3、加载SpringMvcConfig

4、执行@ComponentScan加载对应的bean

5、加载UserController,每个@RequestMapping的名称对应一个具体的方法

6、执行getServletMappings方法,定义所有的请求都通过SpingMVC

单次请求过程

1、发送请求localhost/save

2、web容器发现所有请求都经过SpingMVC,将请求交给SpringMVC处理

3、解析请求路径/save

4、由/save匹配执行对应的方法save()

5、执行save()

6、检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方

请求与响应

请求参数

普通参数:url地址传参,地址参数名与形参变量名相同(名称不匹配在参数前使用@RequestParam("地址参数名")),定义形参即可接收

POJO参数:请求参数名与形参对象属性名相同

数组参数:请求参数名与形参对象属性名相同且请求参数为多个

集合保存普通参数:请求参数名与形参对象属性名相同且请求参数为多个,使用@RequestParam绑定参数关系

接收请求中的json数据

开启自动转换json数据支持

@Configuration @ComponentScan("com.itheima.controller") //开启json数据类型自动转换 @EnableWebMvc public class SpringMvcConfig { }

接收json数据

参数前加@RequestBody

@RequestMapping("/listPojoParamForJson") @ResponseBody public String listPojoParamForJson(@RequestBody List<User> list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "{'module':'list pojo for json param'}"; }

日期类型参数传递

接收参数时,根据不同的日期格式设置不同的接收方式

//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd @RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date, @DateTimeFormat(pattern="yyyy-MM-dd") Date date1, @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){ System.out.println("参数传递 date ==> "+date); System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1); System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2); return "{'module':'data param'}"; }

响应

响应页面:直接返回页面名称

//返回值为String类型,设置返回值为页面名称,即可实现页面跳转 @RequestMapping("/toJumpPage") public String toJumpPage(){ System.out.println("跳转页面"); return "page.jsp"; }

响应文本数据

//返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解 @RequestMapping("/toText") @ResponseBody public String toText(){ System.out.println("返回纯文本数据"); return "response text"; }

响应json数据

//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解 @RequestMapping("/toJsonPOJO") @ResponseBody public User toJsonPOJO(){ System.out.println("返回json对象数据"); User user = new User(); user.setName("dashadiao"); user.setAge(15); return user; }

REST风格

REST简介

REST:表现形式转换

优点:

隐藏资源的访问行为

书写简化

REST风格访问资源时使用行为动作区分对资源进行了何种操作

入门案例

1、设定http请求动作

@RequestMapping(value = "/users",method = RequestMethod.POST) @ResponseBody public String save(){ System.out.println("user save..."); return "{'module':'user save'}"; }

2、设定请求参数(路径变量)

//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{'module':'user delete'}"; }

快速开发

1、将相同的路径前缀提到类前

@Controller @ResponseBody @RequestMapping("/books") public class BookController {

2、将@Controller和@ResponseBody合并为@RestController

@RestController //使用@RestController注解替换@Controller与@ResponseBody注解,简化书写 @RequestMapping("/books") public class BookController {

3、将每个方法的前的@RequestMapping替换为@{行为}Mapping

@PostMapping //使用@PostMapping简化Post请求方法对应的映射配置 @DeleteMapping("/{id}") //使用@DeleteMapping简化DELETE请求方法对应的映射配置 @PutMapping //使用@PutMapping简化Put请求方法对应的映射配置 @GetMapping("/{id}") //使用@GetMapping简化GET请求方法对应的映射配置

SSM整合(注解)

1、创建Maven的web项目

补全项目结构

2、添加依赖

pom.xml添加SSM所需要依赖的jar包

<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.13</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>

配置tomcat服务器

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

3、创建项目包结构

 

config目录存放相关配置类

controller编写Controller类

dao存放Dao接口,使用Mapper接口代理方式没有实现类包

service存放的是Service接口,impl存放接口的实现类

resources存放配置文件,如Jdbc.properties

webapp目录可以存放静态资源

test/java存放测试类

4、创建SpringConfig类

 

@Configuration用来代替xml配置文件

@ComponentScan({"com.my.service"})设定要扫描的包

@PropertySource("classpath:jdbc.properties")配置数据源

@Import({JdbcConfig.class,MyBatisConfig.class})将类注入到容器中

@EnableTransactionManagement开启声明式事务

@Configuration @ComponentScan({"com.my.service"}) @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MyBatisConfig.class}) @EnableTransactionManagement public class SpringConfig { }

5、创建JdbcConfig配置类

 

属性值来源Jdbc.properties文件

public DataSource dataSource()返回数据源

public PlatformTransactionManager transactionManager(DataSource dataSource)事务管理器

public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean public DataSource dataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager ds =new DataSourceTransactionManager(); ds.setDataSource(dataSource); return ds; } }

6、创建MybatisConfig配置类

 

public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource)返回SqlSessionFactoryBean对象,设置扫描包

public MapperScannerConfigurer mapperScannerConfigurer()扫描映射

public class MyBatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.my.domain"); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.my.dao"); return msc; } }

7、创建jdbc.properties

 

提供要连接数据库的信息

MySQL8驱动:com.mysql.cj.jdbc.Driver

MySQL5驱动:com.mysql.jdbc.Driver

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false jdbc.username=root jdbc.password=123456789

8、创建SpringMVC配置类

 

@EnableWebMvc是使用Java 注解快捷配置Spring Webmvc的一个注解。

@Configuration @ComponentScan({"com.my.controller","com.my.config"}) @EnableWebMvc public class SpringMvcConfig { }

9、创建Web项目入口配置类

 

protected Class[] getRootConfigClasses():配置SpringConfig

protected Class[] getServletConfigClasses():配置SpringMvcConfig

protected String[] getServletMappings():设置拦截路径

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[]{"/"}; } }

10、创建数据库及表

create database ssm_db character set utf8; use ssm_db; create table tbl_book( id int primary key auto_increment, type varchar(20), name varchar(50), description varchar(255) )

11、编写模块类

 

public class Book { private Integer id; private String type; private String name; private String description; //添加get/set方法 }

12、编写Dao接口

 

public interface BookDao { @Insert("insert into tbl_book values(null,#{type},#{name},#{description})") public void save(Book book); @Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}") public void update(Book book); @Delete("delete from tbl_book where id = #{id}") public void delete(Integer id); @Select("select * from tbl_book where id = #{id}") public Book getById(Integer id); @Select("select * from tbl_book") public List<Book> getAll(); }

13、编写Service接口和实现类

 

@Transactional注解在代码执行出错的时候能够进行事务的回滚。

bookDao在Service中注入的会提示一个红线提示IDEA在检测依赖关系的时候,没有找到适合的类注入,所以会提示错误提示 但是程序运行的时候,代理对象就会被创建,框架会使用DI进行注入,所以程序运行无影响。

@Transactional public interface BookService { public boolean save(Book book); public boolean update(Book book); public boolean delete(Integer id); public Book getById(Integer id); public List<Book> getAll(); }

@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(); } }

14、编写Contorller类

 

@RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public Result save(@RequestBody Book book) { boolean flag = bookService.save(book); return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag); } @PutMapping public Result update(@RequestBody Book book) { boolean flag = bookService.update(book); return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag); } @DeleteMapping("/{id}") public Result delete(@PathVariable Integer id) { boolean flag = bookService.delete(id); return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag); } @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code =book!=null?Code.GET_OK:Code.GET_ERR; String msg = book !=null?"":"数据查询失败请重试"; return new Result(code,book,msg); } @GetMapping public Result getAll() { List<Book> books = bookService.getAll(); Integer code = books!=null?Code.GET_OK:Code.GET_ERR; String msg = books!=null?"":"数据查询失败请重试"; return new Result(code,books,msg); } }

15、表现层与前端数据传输协议定义

 

对于前端来说,如果后台能够返回一 个统一的数据结果,前端在解析的时候就可以按照一种方式进行解析。开发就会变得更加简单。

为了封装返回的结果数据:创建结果模型类,封装数据到data属性中

为了封装返回的数据是何种操作及是否操作成功:封装操作结果到code属性中

操作失败后为了封装返回的错误信息:封装特殊消息到message(msg)属性中

public class Result { private Object data; private Integer code; private String msg; public Result() {} public Result(Integer code, Object data) { this.data = data; this.code = code; } public Result(Integer code, Object data, String msg){ this.data=data; this.code=code; this.msg=msg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }

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; public static final Integer SAVE_ERR = 20010; public static final Integer DELETE_ERR = 20020; public static final Integer UPDATE_ERR = 20030; public static final Integer GET_ERR = 20040; }

16、异常处理

 

异常的种类及出现异常的原因:

框架内部抛出的异常:因使用不合规导致

数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)

业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)

表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)

工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

1. 各个层级均出现异常,异常处理代码书写在哪一层?

所有的异常均抛出到表现层进行处理

2. 异常的种类很多,表现层如何将所有的异常都处理到呢?

异常分类

3. 表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决?

AOP

@RestControllerAdvice:Rest风格开发的控制器增强类定义上方,为Rest风格开发的控制器类做增强。此注解自带@ResponseBody注解与@Component注解,具备对应的功能

@ExceptionHandler:专用于异常处理的控制器方法上方,设置指定异常的处理方案,功能等同于控制器方法, 出现异常后终止原始控制器执行,并转入当前方法执行。此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception ex){ System.out.println("处理异常"); return new Result(404,null,"存在异常"); } @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex){ //记录日志 //发送消息给运维 //给开发人员发邮件 return new Result(ex.getCode(),null,ex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException ex){ return new Result(ex.getCode(),null,ex.getMessage()); } }

public class SystemException extends RuntimeException { private Integer code; public SystemException(String message, Integer code) { super(message); this.code = code; } public SystemException(String message, Throwable cause, Integer code) { super(message, cause); this.code = code; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }

public class BusinessException extends RuntimeException { private Integer code; public BusinessException(String message, Integer code) { super(message); this.code = code; } public BusinessException(String message, Throwable cause, Integer code) { super(message, cause); this.code = code; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }

拦截器

拦截器概念

一种动态拦截方法调用机制,在SpringMVC中拦截控制器方法的执行

作用:

在指定方法前后执行预先定义的功能

阻止原始方法的执行

入门案例

1、创建一个拦截器类(定义在controller.interceptor包下),实现HandlerInterceptor接口

public class ProjectInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("preHandle..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); } }

2、加载拦截器

类前添加注解@Component,检查SpringMvcConfig类是否能扫描到拦截器

3、在SpringMvcSupport类中重写addInterceptors方法

检查SpringMvcConfig类是否能扫描到SpringMvcSupport类

@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/books"); } }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值