当前位置:   article > 正文

黑马程序员ssm之SpringMVC_黑马程序员springmvc

黑马程序员springmvc

1.SpringMVC简介

属于web层开发技术

2.SpringMVC技术入门案例

1.导入pom.xml坐标

2.把要调用的方法设置成bean

因为是在web层,所以要设置成controller

usercontroller上面加上@Controller标签

里面写方法,上面加上标签:@RequestMapping

                                               @ResponseBody

3.初始化一个springmvcConfig的配置类,专门用来加载springmvc的控制器

  1. @Configuration
  2. @Component("com.itheima.controller")
  3. public class SpringMvcConfig{
  4. }

4.加载SpringMvc环境,并且用mvc技术解决问题

  1. public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
  2. //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
  3. protected WebApplicationContext createServletApplicationContext() {
  4. //初始化WebApplicationContext对象
  5. AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
  6. //加载指定配置类
  7. ctx.register(SpringMvcConfig.class);
  8. return ctx;
  9. }
  10. //设置由springmvc控制器处理的请求映射路径
  11. protected String[] getServletMappings() {
  12. return new String[]{"/"};
  13. }
  14. //加载spring配置类
  15. protected WebApplicationContext createRootApplicationContext() {
  16. return null;
  17. }
  18. }

很方便,因为controller下面可以写很多方法,除了第一个案例要配置的东西有点多之外,其他都还好

3.SpringMvc案例的流程分析

3.Bean加载的控制 

springmvc正常配置就好了

spring要注意一点

1.把controller包排除出去,写的分支细一些

2.写excludeFilters,其实挺固定的

就com.itheima和Controller.class需要改一改

  1. //@ComponentScan({"com.itheima.service","com.itheima.dao"})
  2. //设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
  3. //excludeFilters属性:设置扫描加载bean时,排除的过滤规则
  4. //type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
  5. //classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
  6. @ComponentScan(value="com.itheima",
  7. excludeFilters = @ComponentScan.Filter(
  8. type = FilterType.ANNOTATION,
  9. classes = Controller.class
  10. )
  11. )

在一开始引入springmvc环境的时候还有一种简单的方法

  1. public class ServlectContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
  2. //root配置的是spring
  3. protected Class<?>[] getRootConfigClasses() {
  4. return new Class[]{SpringConfig.class};
  5. }
  6. //ServletConfig配置的是SpringMvc
  7. protected Class<?>[] getServletConfigClasses() {
  8. return new Class[]{SpringMvcConfig.class};
  9. }
  10. //配置的是全部路径
  11. protected String[] getServletMappings() {
  12. return new String[]{"/"};
  13. }
  14. }

4.POSTMAN的测试

可以用来发post或者get请求

5.请求映射路径

避免多个控制器重名的问题:
在控制器上面加上前缀就好了

  1. @RequestMapping("/user")
  2. public class UserController {
  3. //请求路径映射
  4. @RequestMapping("/save")
  5. @ResponseBody
  6. public String save(){
  7. System.out.println("user save ...");
  8. return "{'module':'user save'}";
  9. }
  10. //请求路径映射
  11. @RequestMapping("/delete")
  12. @ResponseBody
  13. public String delete(){
  14. System.out.println("user delete ...");
  15. return "{'module':'user delete'}";
  16. }
  17. }

6.get和post传参

后台怎么接前端的请求 

突然反应过来get和post对于mvc来说是一起接收的吗??没有doget和dopost之分????

太牛啦!!!!!

get怎么发信息

直接在下面写就好

post怎么发信息

SpringMvc怎么解决post乱码的问题

在一开始初始化的config里面加一个过滤器

  1. //乱码处理
  2. @Override
  3. protected Filter[] getServletFilters() {
  4. CharacterEncodingFilter filter = new CharacterEncodingFilter();
  5. filter.setEncoding("UTF-8");
  6. return new Filter[]{};
  7. }

7.五种类型传参

第一种:名字不匹配可以强行让它匹配

  1. @RequestMapping("/commonParamDifferentName")
  2. @ResponseBody
  3. public String commonParamDifferentName(@RequestParam("name") String userName , int age){
  4. System.out.println("普通参数传递 userName ==> "+userName);
  5. System.out.println("普通参数传递 age ==> "+age);
  6. return "{'module':'common param different name'}";
  7. }

第二种:类,直接对着它的名字传就好了

  1. //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
  2. @RequestMapping("/pojoParam")
  3. @ResponseBody
  4. public String pojoParam(User user){
  5. System.out.println("pojo参数传递 user ==> "+user);
  6. return "{'module':'pojo param'}";
  7. }

第三种:数组传参,直接全部传一个变量名就行了,名字写同一个就好了

  1. //数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
  2. @RequestMapping("/arrayParam")
  3. @ResponseBody
  4. public String arrayParam(String[] likes){
  5. System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
  6. return "{'module':'array param'}";
  7. }

第四种:传集合

固定搭配

@RequestParam  List<String> likes

注意,list是可以重复的

8.传递JSON

1.springmvconfig上面加上标签

@EnableWebMvc

2.每一个传递json参数的变量前面,都要加上

@RequestBody

list数组是[]

user类对象是  {}

直接这样传递就好了

9.日期

几种日期格式:

 

  1. @RequestMapping("/dataParam")
  2. @ResponseBody
  3. public String dataParam(Date date,
  4. @DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
  5. @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2
  6. ){
  7. System.out.println("参数传递 date ==> "+date);
  8. System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
  9. System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
  10. return "{'module':'data param'}";
  11. }

记得一点:@DateTimeFormat的标签

括号里面写Pattern写的格式,要和你发送请求的格式相同,要不然匹配不上

为什么可以起到转换的作用呢?底层原理是用到了一个接口

最重要的是,如果想要起到转换器的作用的话,要在springmvconfig里面加上标签

10.响应

1.除了页面跳转直接写String然后直接返回地址外

2.其他都是加上@responsebody标签

   然后返回值的类型选对应想返回的东西就行了

responsebody标签,可以将对象数据转换成JSON数据,然后返回,主要是用到一个接口

要想转换,记得加jkson坐标

11.rest风格

12.restful风格代码

1.requestmethod

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

 2.在路径中要接收参数

   {}

  @pathVarible

  1. @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
  2. @ResponseBody
  3. public String delete(@PathVariable Integer id){
  4. System.out.println("user delete..." + id);
  5. return "{'module':'user delete'}";
  6. }

 

入门案例:

 

 1.controller

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

2.代替requestmapping的四个简易标签

  1. @PostMapping //使用@PostMapping简化Post请求方法对应的映射配置
  2. public String save(@RequestBody Book book){
  3. System.out.println("book save..." + book);
  4. return "{'module':'book save'}";
  5. }
  6. // @RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE)
  7. @DeleteMapping("/{id}") //使用@DeleteMapping简化DELETE请求方法对应的映射配置
  8. public String delete(@PathVariable Integer id){
  9. System.out.println("book delete..." + id);
  10. return "{'module':'book delete'}";
  11. }
  12. // @RequestMapping(method = RequestMethod.PUT)
  13. @PutMapping //使用@PutMapping简化Put请求方法对应的映射配置
  14. public String update(@RequestBody Book book){
  15. System.out.println("book update..."+book);
  16. return "{'module':'book update'}";
  17. }
  18. // @RequestMapping(value = "/{id}" ,method = RequestMethod.GET)
  19. @GetMapping("/{id}") //使用@GetMapping简化GET请求方法对应的映射配置
  20. public String getById(@PathVariable Integer id){
  21. System.out.println("book getById..."+id);
  22. return "{'module':'book getById'}";
  23. }

案例:

后端查询和保存

静态类应该直接放行,不用经过springmvc

ssm整合

1.整合配置

2.功能 

domain

dao:增删改查语句

BookService接口:复制dao里面java语句过去就行了,把对应的功能用日记的形式记录

BookServiceImpl实现类:在实现类上加上@Service标签,并且在语句中自动装配bookdao,重写方法调用bookdao的方法

BookController:类上加上@RestController标签,@RequestMappering("/books)表明映射路径。自动装配@Autowired   bookService ,调用bookService里面的方法。在每个方法上面加上标签,表明@PostMapping或者其他等等。1.有id的加上("/{id}")和@PathVerible  2.有实体类的加上@RequestBody

3.测试

业务层用junit:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =SpringConfig.class)标签

 @TEST

  1. @Autowired
  2. private BookService bookService;
  3. @Test
  4. public void testGetById(){
  5. Book by = bookService.getById(1);
  6. System.out.println(by);
  7. }

表现层用postman

注意修改的时候要给出id的号,别写个Null在那修改

问题分析:

        @PropertySource("jdbc.properties") 错误

        未能在[com.ssm.config.SpringConfig]的类中找到相关的[/jdbc.properties]文件。

解决方案:

Spring配置类改写注解为@PropertySource("classpath:jdbc.properties")即可。

事务管理:

1.开始注解式事务驱动在springconfig上面@EnableTransactionManagement

2.事务平台管理器在jdbcConfig处理

  1. @Bean
  2. public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
  3. DataSourceTransactionManager ds = new DataSourceTransactionManager();
  4. ds.setDataSource(dataSource);
  5. return ds;
  6. }

3.在BookService上面加上@Transactional挂上事务

4.表现层和前端数据的协议

就是要有

Integer code:表示状态

Object data:表示保存的对象

String msg:表示语句

Controller里面创建:

code里面放常量:

  1. package com.itheima.controller;
  2. public class Code {
  3. // public static final Integer SAVE_OK = ;
  4. public static final Integer SAVE_OK=20011;
  5. public static final Integer DELETE_OK=20021;
  6. public static final Integer UPDATA_OK=20031;
  7. public static final Integer GET_OK=20041;
  8. public static final Integer SAVE_ERR=20010;
  9. public static final Integer DELETE_ERR=20020;
  10. public static final Integer UPDATA_ERR=20030;
  11. public static final Integer GET_ERR=20040;
  12. }

Result里面放变量和构造方法:

  1. package com.itheima.controller;
  2. public class Result {
  3. private Object data;
  4. private Integer code;
  5. private String msg;
  6. public Result() {
  7. }
  8. public Result(Integer code,Object data) {
  9. this.data = data;
  10. this.code = code;
  11. }
  12. public Result( Integer code, Object data,String msg) {
  13. this.data = data;
  14. this.code = code;
  15. this.msg = msg;
  16. }
  17. public Object getData() {
  18. return data;
  19. }
  20. public void setData(Object data) {
  21. this.data = data;
  22. }
  23. public Integer getCode() {
  24. return code;
  25. }
  26. public void setCode(Integer code) {
  27. this.code = code;
  28. }
  29. public String getMsg() {
  30. return msg;
  31. }
  32. public void setMsg(String msg) {
  33. this.msg = msg;
  34. }
  35. }

然后再controller里面就可以调用了,表现层封装result

  1. @GetMapping
  2. public Result getAll() {
  3. // System.out.println("getall.....");
  4. List<Book> all = bookService.getAll();
  5. Integer code= all!=null?Code.GET_OK:Code.GET_ERR;
  6. String msg= all!=null?"":"查询失败";
  7. return new Result(code,all,msg);
  8. }

5.异常处理器

 

提供了一个类,作为异常处理器 

在controller包下新建,ProjectExceptionAdvise

加上@RestControllerAdvise

写个方法加上@ExceptionHandler()括号里面是拦截的类型

写的方法注意是Result返回类型,要不然前面接收不到

  1. @RestControllerAdvice
  2. public class ProjectExceptionAdvise {
  3. @ExceptionHandler(Exception.class)
  4. public Result doException(Exception ep){
  5. System.out.println("hhhh,异常啦......");
  6. return new Result(666,null,"异常啦");
  7. }
  8. }

项目异常分类:

1.创建一个exception包

里面放两个类

 

2.设定异常编码code,在之前的code里面加就行了 

3.将可能出现的异常进行包装,包装成我们自己写的异常

在service里面

  1. if(id==1){
  2. throw new BusinessException(Code.BUSINESS_ERR,"输入的不对哦");
  3. }
  4. try{
  5. int i=1/0;
  6. }catch (Exception e){
  7. throw new SystemException(Code.SYSTEM_ERR,"服务器异常",e);
  8. }

4.在异常拦截器里面统一处理我们写的分类异常

  1. @ExceptionHandler(SystemException.class)
  2. public Result doSystemException(SystemException ex){
  3. //记录日志
  4. //发送消息给运维
  5. //发送消息给开发人员,并发送异常ex
  6. System.out.println("hhhh,异常啦......");
  7. return new Result(ex.getCode(),null,ex.getMessage());
  8. }
  9. @ExceptionHandler(BusinessException.class)
  10. public Result doBusinessException(BusinessException ex){
  11. System.out.println("hhhh,异常啦......");
  12. return new Result(ex.getCode(),null,ex.getMessage());
  13. }

6.前后台协议联调

列表功能

先把静态放行,写一个springmvcsupport

1.继承WebMvcConfigurationSupport

2.重写addResourceHandlers

3.定向registry.addResourceHandler.().addResourceLocation();(注意后面地址有个/)

  1. @Configuration
  2. public class SpringMvcSupport extends WebMvcConfigurationSupport {
  3. @Override
  4. protected void addResourceHandlers(ResourceHandlerRegistry registry) {
  5. registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
  6. registry.addResourceHandler("/css/**").addResourceLocations("/css/");
  7. registry.addResourceHandler("/js/**").addResourceLocations("/js/");
  8. registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
  9. }
  10. }

最后SpringMvcConfig扫描到它即可

注意support里面加@

前端可以拿到数据 
  1. getAll() {
  2. axios.get("/books").then((res)=>{
  3. this.dataList=res.data.data;
  4. })
  5. }
添加功能

1.弹出添加页面

  1. //弹出添加窗口
  2. handleCreate() {
  3. this.dialogFormVisible=true;
  4. }

2.前端发送请求添加数据。

这里就是相当于往数据库里面添加了。

然后对前端页面进行修改,这段代码的意思是:当点击添加页面提交按钮键,提交表单上面的信息到后端(就相当于我们postman进行提交数据,只是这里在前端页面进行操作了);然后关闭前端页面;再调用getAll。

  1. //添加
  2. handleAdd () {
  3. axios.post("/books",this.formData).then((res)=>{
  4. this.dialogFormVisible=false;
  5. this.getAll();
  6. })
  7. }

  1. //添加
  2. handleAdd () {
  3. axios.post("/books",this.formData).then((res)=>{
  4. console.log(res.data);
  5. if(res.data.code==20011){
  6. this.dialogFormVisible=false;
  7. this.$message.success("添加成功");
  8. }else if(res.data.code==20010){
  9. this.$message.error("添加失败");
  10. }else{
  11. this.$message.error(res.data.msg);
  12. }
  13. }).finally(()=>{
  14. this.getAll();
  15. })
  16. },

通过影响行计数,来观察添加是否成功

console.log(res.data);可以用来在前端观察后端发来的数据

真的无语,把error写成err,一直不弹窗,一直debug

在打开提交表单的时候,要把formdata清空

  1. //弹出添加窗口
  2. handleCreate() {
  3. this.dialogFormVisible=true;
  4. this.resetForm();
  5. },
  6. //重置表单
  7. resetForm() {
  8. this.formData={};
  9. },
编辑窗口

弹出编辑窗口

  1. //弹出编辑窗口
  2. handleUpdate(row) {
  3. //先根据id查询数据,把数据绑定到表单上
  4. axios.get("/books/"+row.id).then((res)=>{
  5. if(res.data.code==20041){
  6. this.dialogFormVisible4Edit=true;
  7. this.formData=res.data.data;
  8. }else{
  9. this.$message.error(res.data.msg);
  10. }
  11. })
  12. },

编辑

  1. //编辑
  2. handleEdit() {
  3. axios.put("/books",this.formData).then((res)=>{
  4. // console.log(res.data);
  5. if(res.data.code==20031){
  6. this.dialogFormVisible=false;
  7. this.$message.success("修改成功");
  8. }else if(res.data.code==20030){
  9. this.$message.error("修改失败");
  10. }else{
  11. this.$message.error(res.data.msg);
  12. }
  13. }).finally(()=>{
  14. this.getAll();
  15. })
  16. },
删除功能
  1. // 删除
  2. handleDelete(row) {
  3. // axios.delete("/books/"+row.id).then((res)=>{
  4. // if(res.data.code==20021){
  5. // // this.dialogFormVisible=false;
  6. // this.$message.success("删除成功");
  7. // }else if(res.data.code==20020){
  8. //
  9. // this.$message.error("删除失败");
  10. // }else{
  11. // this.$message.error(res.data.msg);
  12. // }
  13. // }).finally(()=>{
  14. // this.getAll();
  15. // })
  16. this.$confirm("此操作永久删除","提示",{
  17. type:'info'
  18. }).then(()=>{
  19. //删除
  20. axios.delete("/books/"+row.id).then((res)=>{
  21. if(res.data.code==20021){
  22. // this.dialogFormVisible=false;
  23. this.$message.success("删除成功");
  24. }else if(res.data.code==20020){
  25. this.$message.error("删除失败");
  26. }else{
  27. this.$message.error(res.data.msg);
  28. }
  29. });
  30. }).catch(()=>{
  31. //取消
  32. this.$message.info("取消删除操作");
  33. }).finally(()=>{
  34. this.getAll();
  35. });
  36. }
  37. }

拦截器

在controller下面创建一个interception包,在里面创建java类来重写三个抽象方法。

加上component标签,让springmvcconfig扫描到它

  1. @Component
  2. public class ProjectInterceptor implements HandlerInterceptor {
  3. @Override
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  5. // return HandlerInterceptor.super.preHandle(request, response, handler);
  6. System.out.println("preHandle.....");
  7. return true;
  8. }
  9. @Override
  10. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  11. // HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
  12. System.out.println("postHandle....");
  13. }
  14. @Override
  15. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  16. // HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
  17. System.out.println("afterCompletion....");
  18. }
  19. }

然后在springmvcsupport放行。当访问books的时候,拦截器进行拦截

  1. @Configuration
  2. public class SpringMvcSupport extends WebMvcConfigurationSupport {
  3. @Override
  4. protected void addResourceHandlers(ResourceHandlerRegistry registry) {
  5. registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
  6. registry.addResourceHandler("/css/**").addResourceLocations("/css/");
  7. registry.addResourceHandler("/js/**").addResourceLocations("/js/");
  8. registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
  9. }
  10. @Autowired
  11. private ProjectInterceptor projectInterceptor;
  12. @Override
  13. protected void addInterceptors(InterceptorRegistry registry) {
  14. // super.addInterceptors(registry);
  15. //当调用books请求的时候,拦截
  16. registry.addInterceptor(projectInterceptor).addPathPatterns("/books");
  17. }
  18. }

注意springmvcsupport和projectinterceptor都要在springmvcconfig里面放行

想要拦截多个路径,在后面接着写就行了

 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");

preHandle里面写false,就无法继续往下走了

拦截器的参数

第三个可以获得我们执行的参数

  1. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  2. String contentType = request.getHeader("Content-Type");
  3. HandlerMethod hm = (HandlerMethod)handler;
  4. System.out.println("preHandle..."+contentType);
  5. return true;
  6. }

第四个,页面跳转 

  1. @Override
  2. //原始方法调用后执行的内容
  3. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  4. System.out.println("postHandle...");
  5. }

第四个,捕捉异常 

  1. @Override
  2. //原始方法调用完成后执行的内容
  3. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  4. System.out.println("afterCompletion...");
  5. }

总的来说是preHandle里面的return false;return true最有用

拦截器链

拦截顺序和你配置在support里面的顺序有关

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/67853
推荐阅读
相关标签
  

闽ICP备14008679号