SpringMVC

1、SpringMVC传参的七种方式(前端传给后端)

1)基本方式传参

@PostMapping("/addDept")
    //方式一:基本方式传参:参数的名字和表单标签及url的名字一致即可
    public String addDept(int dno,String name,String loc){
        //如何接收表单里的值 看上边方法的参数
        Dept dept = new Dept(dno,name,loc);
        System.out.println(dept);

        //默认转发跳转
        return "index";
    }

2)对象传参

@PostMapping("/addDept2")
    //方式二:对象传参:表单标签或URL的参数名和对象的属性名一致即可
    public String addDept2(Dept dept){
        System.out.println(dept);
        //默认转发跳转  forward:走视图解析器
        //重定向跳转 redirect:不走视图解析器  //需要确定页面的路径和扩展名
//        return "index";
        return "redirect:/index.jsp";
    }

3)数组传参

    @PostMapping("/addStudent")
    //数组传参
    public String register(String stuNo,String stuName,String[] hobby){
        Student student = new Student(stuNo,stuName,hobby);
        System.out.println(student);
        return "index";
    }

4)注解传参

@PostMapping("/addStudent2")
    //注解方式  官方推荐
    public String register2(@RequestParam(name = "stuNo") String sNo,
                            @RequestParam(name = "stuName") String name,
                            @RequestParam(name = "hobby",required = false,defaultValue = "")
                            String[] hob){

        //name  表单或url的标签或变量的名字
        //required  是否必须传递这个参数 false不是 默认为true
        //defaultValue  当没有传递这个参数时,默认值就是defaultValue设定的值

        Student stu = new Student();
        stu.setStuNo(sNo);
        stu.setStuName(name);
        stu.setHobby(hob);
        System.out.println(stu);
        return "index";
    }




@GetMapping("/test")
    public String test(@RequestParam(name = "id") int testId,
                       @RequestParam(name = "desc", required = true,defaultValue = "456") String des){
        System.out.println("id=" + testId +",desc=" + des);
        return "index";
    }

5)集合传参

 

get方法

Controller:

@Controller
@RequestMapping("/teacher")
public class TeacherController {
    //集合传参
    @GetMapping("/add")
    public String addTeacher(Teacher teacher){
        System.out.println(teacher);
        return "index";
    }

 
}

url:
 


http://localhost:8080/springmvcpro/teacher/add?

teaName=zhaoyiyi&studentList[0].stuNo=001&studentList[0].stuName=wangyi&

studentList[0].hobby[0]=sing&studentList[0].hobby[1]=run&studentList[1].stuNo=002&

studentList[1].stuName=wangeri&studentList[1].hobby[0]=cook&

studentList[1].hobby[1]=sleep

post方法

Controller

package com.qf.springmvcpro.controller;

import com.qf.springmvcpro.pojo.Student;
import com.qf.springmvcpro.pojo.Teacher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/teacher")
public class TeacherController {


    @PostMapping("/add2")
    public String addTeacher2(Teacher teacher){
        System.out.println("老师姓名:"+teacher.getTeaName());
        System.out.println("学生如下:");
        for(Student stu : teacher.getStudentList()){
            System.out.println(stu);
        }
        return "index";
    }
}

jsp:

<%--
  Created by IntelliJ IDEA.
  User: poison
  Date: 2022/4/14
  Time: 21:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form method="post" action="teacher/add2">

        <p>讲师姓名:<input type="text" name="teaName"/></p>
        <%--这就是一个节点--%>
        <div class="divStudent">
            <p>学生学号:<input type="text" name="studentList[0].stuNo"/></p>
            <p>学生姓名:<input type="text" name="studentList[0].stuName"/></p>
        </div>
        <hr/>
        <%--另一个节点--%>
        <div class="divStudent">
            <p>学生学号:<input type="text" name="studentList[1].stuNo"/></p>
            <p>学生姓名:<input type="text" name="studentList[1].stuName"/></p>
        </div>
        <hr/>
        <%--另一个节点--%>
        <div class="divStudent">
            <p>学生学号:<input type="text" name="studentList[2].stuNo"/></p>
            <p>学生姓名:<input type="text" name="studentList[2].stuName"/></p>
        </div>
        <p><input type="submit" value="添加讲师"/></p>
    </form>
</body>
</html>

6)路径传参

使用Restful风格编程

package com.qf.springmvcpro.controller;

import com.qf.springmvcpro.pojo.Dept;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;


@Controller
@RequestMapping("/dept") //加两级路径 不区分请求方式 是get还是post  get和post都可以
public class DeptController {




    //{}里边的名字可随意填写 和下边@PathVariable("dno") 对应即可
    @GetMapping("/addDept3/{dno}/{name}/{loc}")
    //括号前边的是 @GetMapping("/addDept3//{duno},{name},{loc}") 中{}里的名字
    //括号后边的是给pojo赋值的变量名 可以随意起名
    //类型和pojo相同
    public String addDept3(@PathVariable("dno") int deptNo,
                           @PathVariable("name") String dName,
                           @PathVariable("loc") String loc){
        Dept dept = new Dept(deptNo,dName,loc);
        System.out.println(dept);
        return "index";
    }
}

url

http://localhost:8080/springmvcpro/dept/addDept3/9093/zhangsn/beijing

7)Json传参

前端页面

function addDept() {
    //声明一个JSON数据
    //【注意】json的key要和后台java对象的属性名要相同,否则传递错误
    var json1={"deptNo":9050,"dName":"开发部","loc":"设计城"};
    //把JSON转成字符串
    var strJson=JSON.stringify(json1);
    $.ajax({
        url:"dept/add4.action",
        type:"post",
        dataType:"text",//得到的数据类型是字符串
        contentType:"application/json", //【***注意***】告知服务器传递的是JSON
        async:true,
        data:strJson,//传递数据
        success:function (result) {
            if(result=="true"){
                alert("添加成功!");
            }else{
                alert("添加失败!");
            }
        }
    });
}

控制器

//前端传递JSON
@PostMapping("/add4.action")
@ResponseBody
public String addDept4(@RequestBody Dept dept){
    //@RequestBody  把前端传递的JSON转成对象
    System.out.println("前端传递数据:"+dept);
    return "true";
}


2、SpringMVC的五种收参方式(后端传给前端)

在没有使用SpringMVC时,传值方式:

1)使用作用域 优先使用request session

使用request作用域存值,必须要转发到视图

使用sesson作用域存值,转发、重定向都可以

实现步骤:

导入需要的jar

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

使用作用域存储数据

@GetMapping("/find")
public String findDept(HttpServletRequest request){
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9091,"1部","大连");
    Dept dept2=new Dept(9092,"2部","北京");
    list.add(dept1);
    list.add(dept2);
    //如何把数据传递给deptlist.jsp页面
    request.setAttribute("data",list);
    //转发
    return "deptlist";
}

视图获取数据


<html>
<head>
    <title>部门列表</title>
</head>
<body>
<table>
    <tr>
        <td>部门编号</td>
        <td>部门名称</td>
        <td>部门位置</td>
    </tr>
    <c:forEach  items="${requestScope.data}" var="dept">
        <tr>
            <td>${dept.deptNo}</td>
            <td>${dept.dName}</td>
            <td>${dept.loc}</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

2)Model传值

//使用Model传值给视图
@GetMapping("/find1")
public String findDept1(Model model){
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9093,"3部","大连");
    Dept dept2=new Dept(9094,"4部","北京");
    list.add(dept1);
    list.add(dept2);
    //把数据存入到Model
    model.addAttribute("data",list); //本质还是使用request进行传递
    return "deptlist";
}

前端获取数据方式不变

3)ModelAndView传值

//使用ModelAndView传值
@GetMapping("/find2")
public ModelAndView findDept2(){
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9093,"3部","大连");
    Dept dept2=new Dept(9094,"4部","北京");
    list.add(dept1);
    list.add(dept2);
    //创建ModelAndView对象
    ModelAndView modelAndView=new ModelAndView();
    //设置视图的名字
    modelAndView.setViewName("deptlist");
    //赋值数据
    modelAndView.addObject("data",list);
    //视图解析器解析modelAndView
    return modelAndView;
}

前端获取数据方式不变

4)@SessionAttributes 传值

本质就是使用session进行传值

 

5)json传值

控制器得到数据,对象,需要把集合转成JSON

原来: FastJson----手动添加依赖,进行转换

使用框架后,SpringMVC通过注解@ResponseBody把返回的数据,转成JSON格式的字符串

@ResponseBody使用Jackson进行转换

添加jackson的jar依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

前端页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
    <script>
        function getDepts() {
            //发出AJAX请求
            $.ajax({
                url:"dept/find4.action",
                type:"get",
                dataType:"json",
                async:true,
                success:function (jsonData) {
                    var str=JSON.stringify(jsonData);
                    alert(str);
                }
            });
        }
    </script>
</head>
<body>
<input type="button" value="获取部门数据" onclick="getDepts()"/>
</body>
</html>

控制器

@GetMapping("/find4.action")
@ResponseBody //1、把返回的数据转成JSON,在核心核心控制器进行转换  2、不走视图解析器
public List<Dept> findDept4(){
    //方法返回的字符串在控制器里默认是转发或重定向的视图名
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9091,"1部","大连");
    Dept dept2=new Dept(9092,"2部","北京");
    list.add(dept1);
    list.add(dept2);
    return list;
}

概念:Handler 在控制器中,请求的路径以及对应的方法统称为Handler

@GetMapping("/find5.action")
public @ResponseBody List<Dept> findDept5(){
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9091,"1部","大连");
    Dept dept2=new Dept(9092,"2部","北京");
    list.add(dept1);
    list.add(dept2);
    return list;
}

问题:如果控制器中所有的方法都返回JSON格式的字符串,每个方法都添加@ResponseBody 比较繁琐

解决:使用@RestController注解

@RestController=@Controller+@ResoponseBody

package com.qf.springmvcpro.controller;

import com.qf.springmvcpro.pojo.Dept;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/dept2")
public class DeptController2 {

    @GetMapping("/find1.action") //无需添加@ResponseBody
    public List<Dept> findDept1(){
        List<Dept> list=new ArrayList<Dept>();
        Dept dept1=new Dept(9091,"1部","大连");
        Dept dept2=new Dept(9092,"2部","北京");
        list.add(dept1);
        list.add(dept2);
        return list;
    }
    @GetMapping("/find2.action")
    public Dept findDept2(){
        Dept dept2=new Dept(9092,"2部","北京");
        return dept2;
    }
}

【说明】如果方法本身就是字符串,则不需要JSON转换

//如果数据本身就已经是字符串,无需使用@ResponseBody注解进行转换
@GetMapping(value = "/test.action",produces = "text/html;charset=utf-8")
@ResponseBody
public String test(){
    return "你好!";
}


3、中文乱码解决

SpringMVC框架自带了过滤器,拦截所有请求,以及响应,进行编码设置

在web.xml文件中进行配置

<filter>
    <filter-name>codingSet</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--告知CharacterEncodingFilter过滤器,我们需要设置的编码方式-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>codingSet</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


4、转发、重定向

转发:默认就就是转发 retrun "forward:index";

重定向: return ”redirect:/index.jsp“;

【说明】

1、需要指定路径和扩展名

2、重定向不走视图解析器

使用的时候有选择:

1、为了防止因刷新而产生的url或表单的重复提交,添加、修改、删除后,使用重定向进行页面跳转

2、查询之后可以使用转发


5、在SpringMVC框架下,静态资源处理

静态资源:html页面 css样式 图片等资源 JavaScript代码

问题:当请求静态资源的时候,tomca拦截静态请求到DispacherServlet中,检索Controller中有无对应的请求路径,如果有,则调用对应的方法,如果没有抛404异常。

解决方案:

1、由于DispacherServlet拦截静态的请求,并没有放行,通过配置让其对静态资源放行,放行给tomcat处理静态资源的servlet, DefaultServlet

在springMVC的配置文件中

<!--对静态资源的请求放行,放行给DefaultServlet
    DefaultServlet就回调到对应路径下寻找静态资源,响应给用户
-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>

2、在拦截请求的时候不使用/ 而使用后缀的方式

<servlet-mapping>
    <servlet-name>servlet</servlet-name>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>
@GetMapping("/find3.action")
public String findDept3(Model model){
    List<Dept> list=new ArrayList<Dept>();
    Dept dept1=new Dept(9093,"3部","大连");
    Dept dept2=new Dept(9094,"4部","北京");
    list.add(dept1);
    list.add(dept2);

    //使用model存值
    model.addAttribute("data1",list);  //存入session中
    model.addAttribute("data2",dept1); //存入到session中
    return "deptlist";
}

只拦截以action为结尾的请求,到DispacherServlet,别的请求不拦截,最终到达DefaultServlet里


6、JACKSON常用注解

@JsonIgnore:忽略,对应的属性不会被序列化成json数据

private int deptNo;
private String dName;
@JsonIgnore //告知JackSon在转成json数据时,忽略掉当前属性
private String loc;

@JsonProperty 序列化成json数据时,json的key的别名

@JsonProperty("dno")
private int deptNo;
@JsonProperty("name")
private String dName;

@JsonFormat 对默认的时间类型进行格式化

pattern:时间格式 timezone:时区 东八时区

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date date;

String str="";

if(str.length==0){}

@JsonInclude null值的属性不会序列化成json数据

Include.NON_DEFAULT  属性为默认值不序列化 (例如int为0,Object为null)
Include.NON_EMPTY     属性为 空("") 或者为 NULL 都不序列化
Include.NON_NULL        属性为NULL 不序列化

@JsonInclude(JsonInclude.Include.NON_NULL)  //null值的属性就不会被序列化成JSON数据
//@JsonInclude(JsonInclude.Include.NON_EMPTY) //"".lentgh==0 或null值的属性也不会被序列化成JSON数据
private String desc;

@JsonSerialize  用于在序列化时嵌入我们自定义的代码

//声明总薪资的属性
//使用了自定义的序列化属性
@JsonSerialize(using = MySerializable.class)
private Double salary=10000.126;

package com.qf.springmvcpro.util;


import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.math.BigDecimal;

public class MySerializable extends JsonSerializer<Double> {

    public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        //参数value,就是属性的值
        //将属性值 小数位数保留两位,然后四舍五入
        String number= BigDecimal.valueOf(value).setScale(2,BigDecimal.ROUND_HALF_UP).toString();
        //将转换后的值进行输出---转成json的数据值
        gen.writeNumber(number);
    }
}


7、FastJson的使用及常用注解

@ResponseBody,默认使用jackson ,可以用fastjson进行替换

1、添加fastjson的依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.54</version>
</dependency>

2、通过springMVC的配置文件的配置,使用fastjson替换掉jackson

<!--使用fastjson替换掉jackson-->
<mvc:annotation-driven>
    <!--安装FastJson转换器-->
    <mvc:message-converters>
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
            <!--告知fastjson  转换的类型  json-->
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

3、使用FastJson

【说明】@ResponseBody @ReauestBody @RestController 使用与之前使用jackson时没有任何区别

FastJson的注解与Jackson不同

@JSONField  格式化

 @JSONField(format = "yyyy-MM-dd hh:mm:ss") //格式化
    private Date date;

@JSONField   别名

@JSONField(name = "name") //别名
    private String dName;

@JSONField   忽略掉空值及""(“” 双引里边没有值)

@JSONField(serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)//忽略掉空值及“”
    private String desc;

@JSONField    被忽略

@JSONField(serialize = false) //被忽略
    private String loc;

 @JSONField     使用自定义序列化属性

 @JSONField(serializeUsing = MapSerializer.class) //使用自定义序列化属性
    private Double totalSal=10000.126;


8、异常解析器

异常处理原则:dao 有异常时,向上抛

service 有异常时,继续向上抛

controller 有异常时,捕获

如果controller中的每个handler方法都进行异常捕获的话,代码冗余、繁琐,使用springMVC的异常解析器来简化异常捕获

异常解析器的设计思想:每个handler发生异常后,抛出异常,异常集中抛给异常解析器,异常解析器,对异常同一处理,简化了异常处理

编码:

1、根据不同的异常,创建不同的显示页面

2、定义异常解析器

package com.qf.springmvcpro.util;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyExceptionResolver implements HandlerExceptionResolver {
    //handler方法中的异常都跑到此类的下面方法中
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        //同一处理异常
        //打印堆栈上的异常信息
        e.printStackTrace();
        ModelAndView modelAndView=new ModelAndView();
        //判断异常类型,不同异常,跳转到不同页面
        if(e instanceof NullPointerException){
            modelAndView.setViewName("redirect:/err/null.jsp");
        }else if(e instanceof NumberFormatException){
            modelAndView.setViewName("redirect:/err/format.jsp");
        }else if(e instanceof IOException){
            modelAndView.setViewName("redirect:/err/io.jsp");
        }else{
            modelAndView.setViewName("redirect:/err/exception.jsp");
        }
        return modelAndView;
    }
}

3、注册异常解析器

在springmvc的配置文件中

<!--注册异常解析器-->
<bean class="com.qf.springmvcpro.util.MyExceptionResolver"></bean>

4、handler的方法中抛出异常即可

package com.qf.springmvcpro.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class ExceptionController {

    @GetMapping("/test1.action")
    public String test1() throws NullPointerException{
        String str=null;
        System.out.println(str.length());
        return "success";
    }
    @GetMapping("/test2.action")
    public String test2() throws NumberFormatException{
        String str="a";
        int num=Integer.parseInt(str);
        System.out.println(num);
        return "success";
    }
}

原理:springmvc捕获抛出的所有异常,执行代理对象(异常处理器),统一处理


9、拦截器

概念:拦截特定的请求,转移到类中,执行特定的方法,这个类就称为拦截器

SpringMVC的拦截器,在handler方法执行之前、或之后执行的方法,减少handler方法中的代码冗余

时间点:在handler之前

之后

1、定义拦截器

package com.qf.springmvcpro.interceptor;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//自定义的拦截器
public class MyInterCeptor implements HandlerInterceptor {
    //在执行handler方法之前执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行拦截器的前置方法");
        //true:请求继续向下发出,去执行handler方法
        //false:请求中断
        return true;
    }
    //在handler方法执行之后:进一步的响应
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("执行拦截器的后置方法");
    }
    //在handler方法执行之后:在资源回收时
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("执行拦截器的after");
    }
}

2、配置拦截路径

<!--配置拦截路径-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/*.action"/>
        <!--刨除以下请求路径-->
        <mvc:exclude-mapping path="/dept2/*.action"/>
        <bean class="com.qf.springmvcpro.interceptor.MyInterCeptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

【说明】作用,为了提取handler中的冗余代码

使用场景:执行权限

认证---登录


10、文件的上传

1、添加jar

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
    <exclusions>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2、上传页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="file/upload">
    <p>文件:<input type="file" name="source"/></p>
    <p><input type="submit" value="上传"/></p>
</form>
</body>
</html>

3、配置文件上传解析器

<!--文件上传解析器
    【说明】文件上传解析器的id必须是multipartResolver
    -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--配置:文件的最大限制  单位是byte查出后抛出MaxUploadSizeExceededException异常 -->
    <property name="maxUploadSize" value="102410000"></property>
</bean>

4、handler方法

package com.qf.springmvcpro.controller;

import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Controller
@RequestMapping("/file")
public class FileController {
    @PostMapping("/upload.action")
    public String upload(String userName, MultipartFile source, HttpSession session) throws IOException {
        //获取文件的原始名称
        String fileName=source.getOriginalFilename();
        //唯一名称
        String unique= UUID.randomUUID().toString();
        //获取文件的后缀
        String ext= FilenameUtils.getExtension(fileName);
        //新名字
        String newName=unique+"."+ext;
        System.out.println("文件的新名字:"+newName);

        //获取文件的类型
        String type=source.getContentType();
        System.out.println("文件的类型:"+type);

        //把相对路径转换成物理路径
        String realPath=session.getServletContext().getRealPath("/upload_file");
        System.out.println("物理路径:"+realPath);

        //文件上传
        File file=new File(realPath+"\\"+newName);
        source.transferTo(file);
        return "index";
    }
}

【注意】target下是否存在upload_file这个路径,如果不存在则手动创建

文件的大小如果查过文件上传解析器的限制,则抛出MaxUploadSizeExceededException异常


11、文件下载

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="file/download.action?name=2.png">下载</a>
</body>
</html>
@GetMapping("/download.action")
public void downLoad(String name, HttpSession session, HttpServletResponse response) throws IOException {
    System.out.println("要下载的文件名:"+name);
    //找到下载路径
    String path=session.getServletContext().getRealPath("/upload_file");
    //完整的下载路径
    String realPath=path+"\\"+name;
    //设置响应头信息
    response.setHeader("content-disposition","attachment;filename="+name);

    //读取的同时写入客户端
    IOUtils.copy(new FileInputStream(realPath),response.getOutputStream());
    //return "index";
}

【说明】把图片上传到服务器的某个路径下,造成一个问题就是,当Tomcat重启或关闭后,清理自己的目录

存储路径不在项目下即可


12、验证码

作用:防止暴力操作,输入的验证码必须和生成的验证码(同时存于session中)要一致,如果不一致,则不进一步进行操作

场景:注册、登录

验证的实现思路:是一张图片(固定尺寸)

声明一个数组 char[] ary{'2','3'} 8个数字、字母,刨除掉 不易分辨 汉字

随机生成干扰点 干扰线

重要:随机选取指定个数的字符,画到图片的同时,存入session

【说明】数据库并不存储,

1、引入验证码jar

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
    <exclusions>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2、配置验证码信息,在web.xml文件中配置

<!--配置验证码信息-->
<servlet>
    <servlet-name>kap</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    <!--验证码图片的边框-->
    <init-param>
        <param-name>kaptcha.border</param-name>
        <param-value>no</param-value>
    </init-param>
    <!--验证码的长度-->
    <init-param>
        <param-name>kaptcha.textproducer.char.length</param-name>
        <param-value>5</param-value>
    </init-param>
    <!--验证码的组成字符-->
    <init-param>
        <param-name>kaptcha.textproducer.char.string</param-name>
        <param-value>23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ</param-value>
    </init-param>
    <!--设置存入session后,session的key-->
    <init-param>
        <param-name>kaptcha.session.key</param-name>
        <param-value>checkcode</param-value>
    </init-param>
    <!--设置背景-->
    <init-param>
        <param-name>kaptcha.background.clear.to</param-name>
        <param-value>210,233,240</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>kap</servlet-name>
    <url-pattern>/kaptcha</url-pattern>
</servlet-mapping>

3、在页面上应用验证码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <script src="js/jquery-3.4.1.min.js"></script>
    <script type="text/javascript">
        //动态获取添加事件
        $(function () {
            $("#cap").click(function () {
                //刷新验证码
                var path=$(this).attr("src")+"?"+new Date().getTime();
                $(this).attr("src",path);
            });
        });
    </script>
</head>
<body>
<form method="post" action="user/reg.action">
    <p>账号:<input type="text" name="userId" /></p>
    <p>名称:<input type="text" name="userName" /></p>
    <p>验证码:<input type="text" name="code" />
        <img src="kaptcha" title="看不清,单击换一张" style="width: 100px; height: 30px" id="cap">
    </p>
    <p><input type="submit" value="注册"/></p>
</form>
</body>
</html>

4、handler中

package com.qf.springmvcpro.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/user")
public class UserController {
    @PostMapping("/reg.action")
    public String register(String userId, String userName, String code, HttpSession session){
        //先判断验证码是否输入正确
        //取出session中存储的验证码
        String sessionCode=(String) session.getAttribute("checkCode");
        if(code.equals(sessionCode)){
            System.out.println("验证码正确");
            //调用service
            return "index";
        }else{
            System.out.println("验证码错误");
            System.out.println("生成的验证码:"+sessionCode+",输入的验证码:"+code);
            return "redirect:/err/exception.jsp";
        }
    }
}


13、RESTFUL

有两个要求:

1、请求资源唯一

在类的上方加RequestMapping

使用路径传参

2、不同的操作请求,对应不同的method

查询:get

添加:post

修改:put

删除:delete

【说明】返回的都是JSON字符串


14、跨域

新建前端项目,请求当前java项目的内容:http://localhost:8081/springmvcpro/dept2/find1.action

前端页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
		<script>
			$(function(){
				//发出AJAX请求
				$.ajax({
					type:"get",
					url:"http://localhost:8081/springmvcpro/dept2/find1.action",
					async:true,
					dataType:"json",
					success:function(jsonData){
						alert(JSON.stringify(jsonData));
					}
				});
			})
		</script>
	</head>
	<body>
		
	</body>
</html>

请求路径:

http://127.0.0.1:8020/pro210502/index.html

报错:

报错原因分析:

浏览器为了安全考虑,有同源策略,当前浏览器服务的协议、域名(IP)、端口号,和AJAX所请求的服务中的协议、域名、端口号中有任何一个不同的,则AJAX请求正常发出,但是拒绝接收响应。

域=协议+IP+端口号

解决方案:

1、@CrossOrigin,在后台,添加信任,允许某个域进行跨域请求

2、在前端设置允许跨域,前后端分离后,不会把前端的cookie传入到后台

设置允许携带cookie

 跨项目路径要写完整


15、SpringMVC的请求流程---重要

1、在web.xml拦截所有请求,把请求拦截到DispatcherServlet中

2、DispatcherServlet在创建后,读取SpringMVC的配置文件

3、DispatcherServlet在创建后,到IoC容器中,寻找Controller对象,使用RequestMapping中的url为key,使用Controller对象作为Value值,把Controller对象存入map集合中,当请求到达后,通过url找到对应的Controller对象,称为HandlerMapping,

4、HandlerAdapter 适配,通过url拼接的方式,找Controller中对应的方法

5、 先执行拦截器 然后执行对应的handler方法(参数绑定过程) 再执行拦截器

6、生成ModelAndView :存数据,视图名等 返回到DispatcherServlet中

7、通过视图解析器ViewResolver找到视图

8、解析Model里的数据,渲染到视图上

9、响应到客户端


总结:

@Autowired是调用bean工厂中的对象

@Bean 是往bean工厂中创建对象

       

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值