SpringMVC

目录

什么是MVC

Spring MVC项目

Spring MVC 连接客户端与服务器

@ResponseBody注解

@RequestMapping注解

获取请求参数

获取单个参数

获取对象类型的参数

后端参数重命名

 接收json格式数据

 获取URL参数

上传文件

获取cookie

获取Session

获取Header

返回数据

返回静态页面

返回json数据 

请求转发

请求重定向

 请求转发和请求重定向的区别


Spring Web Mvc是基于Servlet ApI构建的原始Web框架,从一开始就包含在Spring框架中

Spring MVC是一个web框架,是和Spring框架一起诞生的,是Spring框架的Web模块,而SpringBoot是为了更加方便高效的使用Spring框架诞生的

什么是MVC

MVC是Model View Controller的缩写,是软件工程中的一种软件架构模式,将软件系统分为模型,视图,控制器三个部分

1、Model(模型)是应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据

2、View(视图)是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的

3、Controller(控制器)是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据

MVC和Spring MVC的关系

MVC是一种思想,而Spring MVC是对MVC思想的具体实现

Spring MVC项目

在创建Spring Boot项目时,选择了Spring Web依赖,就相当于创建了Spring MVC项目

去掉勾选,就可以将目录展开了 

Spring MVC 连接客户端与服务器

@Controller//在框架启动时,创建对象 并注册入框架
public class Hello {
    @ResponseBody
    @RequestMapping("/hello")//设置路由地址
    public String print() {
        return "hello.html";
    }
}

 我们可以使用http://127.0.0.1:8080/hello访问到服务器,客户端和服务器之间建立了连接

这里,要介绍两个注解:@ResponseBody @RequestMapping

@ResponseBody注解

Spring MVC 默认返回的是视图名称(xxx.html)@ResponseBody告诉浏览器,服务器返回的是一个数据,而不是静态页面

没有@ResponseBody注解,返回静态页面的名称

 

加了@ResponseBody,返回的是数据,这个数据存储在Body部分

@RequestMapping注解

1、注解作用

这个注解用于注册接口的路由映射

路由映射:当用户访问一个url时,将用户的请求对应到程序某一个类的某个方法

@RequestMapping注解可以加到类上,一定加到方法上

注解如果加到类上,就设计了一级路由;但是方法一定有对应路由映射,否则无法被访问

2、请求类型

1、@RequestMapping注解默认支持POST请求 GET请求

 2、method属性可以指定请求类型

@Controller//在框架启动时,创建对象 并注册入框架
public class Hello {
    @ResponseBody
    @RequestMapping(value = "/hello",method = RequestMethod.POST)//设置路由地址
    public String print() {
        return "hello.html";
    }
}

只可以接收POST请求,不可以接收其他请求类型

 3、为了简化对请求方法限制 的写法,提供了其他注解:例如@GetMapping和@PostMapping

@GetMapping:请求方法类型为GET

@Controller//在框架启动时,创建对象 并注册入框架
public class Hello {
    @ResponseBody
  @GetMapping("/hello")
    public String print() {
        return "hello.html";
    }
}

获取请求参数

获取单个参数

在之前的Servlet项目内,获取请求的参数,通过继承HttpServlet类重写doxxx方法,通过HttpServletRequest内置方法实现

其中get请求的参数在QueryString中,使用getParameter()方法来获取参数

其中post请求的参数在body中,使用getReader()方法来获取body内容


@WebServlet("/getinf")
public class GetInf extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        resp.getWriter().write("id= " + id);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedReader reader = req.getReader();//读取body内容
        String ret = reader.readLine();
        resp.getWriter().write(  ret);
    }
}

 

 在Springmvc项目,方法传入参数即可,可以同时支持get和post方法

@Controller
public class GetInfo {
    @ResponseBody
    @RequestMapping("/getinfo")
    public String print(Integer id) {//这里 使用Integer类型 可以防止参数不存在为null,从而报错
        if (id == null)
            return null;
        return "id= " + id;
    }
}

获取对象类型的参数

前端给后端发送的也可能是一个对象

在servelt时期,代码如下:

public class Student {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
@WebServlet("/getstudent")
public class GetStudent extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Student student = new Student();
        Integer id = Integer.valueOf(req.getParameter("id"));
        String name = String.valueOf(req.getParameter("name"));
        Integer age = Integer.valueOf(req.getParameter("age"));
        student.setId(id);
        student.setName(name);
        student.setAge(age);
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write(String.valueOf(student));
    }
}

在Spring MVC中:方法参数设置为对象类型即可

@Data
public class Student {
    private int id;
    private String name;
    private int age;
}
@Controller
public class GetStudent {
    @RequestMapping("/getstudent")
    @ResponseBody
    public Student getStudent(Student student) {
        return student;
    }
}

 也就是说,sevlet时期,实现同一个功能,要分别重写post和get请求,调用不同的方法实现,比较复杂

Spring  mvc只需要一个方法,默认同时支持POST、GET请求,同时SpringMVC会自己调整数据返回的类型(json/html等)

后端参数重命名

前端传递的参数名称要和后端匹配,但是我们采用前后端分离写项目,很有可能产生参数命名不匹配的问题,这时,可以使用@RequestParma注解来重命名前后端的参数值

@Controller
public class GetInfo {
    @ResponseBody
    @RequestMapping("/getinfo")
    public String print(@RequestParam("userid") Integer id) {
        if (id == null)
            return null;
        return "id= " + id;
    }
}

 

@RequestParam("userid") Integer id 让前端的参数名userid,可以被替换为后端的参数名id,从而正常使用后端程序

但是,如果此时前端传递的参数名是id,程序会报错,因为此时后端可以接受的前端参数名是userid,且要求这个参数是必须要传的;

可以通过@RequestParam注解的requied参数设置是否一定要传入userid参数:如果requied=true,表示前端一定要传入userid参数,如果不传入,后端程序报错;如果requied=false,表示前端不一定要传入userid参数,如果传入,后端程序正常使用,如果不传入,后端程序也不会报错,只不过不能使用到后端对应方法而已

@Controller
public class GetInfo {
    @ResponseBody
    @RequestMapping("/getinfo")
    public String print(@RequestParam(value = "userid",required = false) Integer id) {
        if (id == null)
            return null;
        return "id= " + id;
    }
}

 

 接收json格式数据

在servlet中,接收json格式的数据,要手动引入jackson依赖,调用第三方库提供的方法

class Stu {
    public int id;
    public String name;
    public int age;

    @Override
    public String toString() {
        return "Stu{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

@WebServlet("/studentjson")
public class GetStudentJson extends HttpServlet {
    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解析body部分的数据 生成对象
        Stu stu = objectMapper.readValue(req.getInputStream(), Stu.class);
        resp.setContentType("application/json;charset=UTF-8");
        resp.getWriter().write(stu.toString());
    }
}

 在SpringMVC中,前端发出json格式的数据(字符串格式),后端使用@RequestBody注解表示参数为json格式,框架会自己按照json数据来处理

@Controller
public class GetInfo {
    @ResponseBody
    @RequestMapping("/getinfo")
    public String print(@RequestBody String id) {
        if (id == null)
            return null;
        return  id;
    }
}

 如果不使用@RequestBody注解,前端参数就无法被后端获取

 获取URL参数

有的需要获取的参数不是URL的QueryString或者body部分,而是其他部分的数据

比如:https://mp.csdn.net/mp_blog/creation/editor

可能会获取参数my_blog或者creation部分

 需要使用@PathVariable注解

@Controller
public class GetUrl {
    @RequestMapping("/get/{id}/{name}/{address}")//路由地址是 get/id/name/address
    @ResponseBody
    public String get(@PathVariable Integer id, @PathVariable String name) {
        return id + name;
    }
}

上传文件

先创建post请求,用于上传文件

当前端的form表单包含有文件上传时;form表单中的数据编码类型要写 enctype="multipart/form-data" 才能上传文件,该编码类型将会以二进制的形式上传数据。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 根据form表单 实现文件上传 -->
    <form action=UploadServlet" method="post" enctype="multipart/form-data"><!-- 数据类型是文件 -->   
 <input type="file" name="filename" >


 <input type="submit" value="上传"> 
 <!-- form表单点击后提交请求 -->
</form>
</body>
</html>

在servlet时,上传文件如下所示:

我们先尝试改掉post请求的action,让其跳转到其他网页,和后端暂时分离,执行前端后抓包观察请求信息

浏览器发送上传文件请求时将文件名存储在Request Head里的Content-Disposition里,但Content-Disposition得值里除了文件名信息还有一些其他信息,所以只能通过字符串截取的方式获取文件的后缀名。

@WebServlet("/UploadServlet")
@MultipartConfig//Servlet3.0 给HttpServletRequest 类 上传文件的功能提供支持,表示现在处理的请求是 multipart/from-data 类型//Servlet3.0将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作。
public class FileUpLoad extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        //通过表单file控件(<input type="file" name="filename">)的名字直接获取Part对象
        Part part = req.getPart("filename");//根据获取上传组件 传入input标签的name值

        //我们此时需要获取的是文件名称
        // Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
        String header = part.getHeader("Content-Disposition");
        //得到文件名称
        String filename = getFileName(header);
        System.out.println(filename);
        //指定文件 上传的路径
        String savePath = "C:\\Users\\30283\\Pictures\\picture";
        System.out.println(savePath);

        //得到新的路径 UUID会保证生成不重复的数据
        String root = savePath + "\\" + UUID.randomUUID().toString() + filename;
        System.out.println("文件路径" + root);
        part.write(root);
        part.delete();//删除产生的额外内容
        resp.getWriter().write("上传成功");

    }

    /**
     * 根据请求头解析出文件名
     * 请求头的格式:
     * 火狐和google浏览器下:
     * form-data; name="file"; filename="snmp4j--api.zip"
     * IE浏览器下:form-data; name="file"; filename="E:\snmp4j--api.zip"
     * <p>
     * <p>
     * header:请求头
     *
     * @return 文件名
     */
    private String getFileName(String header) {
      //兼顾各种浏览器 第一步先获取filename后的内容
        String filename = header.substring(header.lastIndexOf("=") + 2,header.length()-1);
        System.out.println(filename);
        //火狐和google浏览器下: 得到 snmp4j--api.zip IE浏览器下 得到E:\snmp4j--api.zip
        //第二步 获取不同的浏览器的名称
        int index = filename.lastIndexOf('\\');
        filename = filename.substring(index + 1);//从路径中获取名称
        // IE浏览器:snmp4j--api.zip"
        //火狐和google浏览器下: "snmp4j--api.zip"
        System.out.println(filename);

        return filename;
    }

浏览器上传一个文件之后,会在 指定目录C:\\Users\\30283\\Pictures\\picture下生成文件

 在SpringMVC 中,@RequestPart这个注解用在multipart/form-data表单提交请求的方法上,主要用来搭配springboot接收MultipartFile类型的文件。

@Controller
@Slf4j
public class UploadServlet {
    @ResponseBody
    @PostMapping("/uploadservlet")
    public Boolean upload(@RequestPart("filename") MultipartFile file) {
        Boolean result = false;
        try {
            file.transferTo(new File("C:\\Users\\30283\\Pictures\\picture\\new.jpg"));
            result = true;
            log.info("上传成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }
}

 在这个代码中,存在问题:

1、文件上传的路径是写死的,每一次新上传,就会覆盖之前的内容

2、文件类型也是写死的

第一步:让平台可以变化:

在windows系统,是从C盘或者D盘等开始的,Linux系统,是从root这个根目录开始的;一个项目,可以运行在多个平台,我们要对此进行配置,让多个平台都可以使用

创建本地和Linux的配置文件,命名规定application-开头

有三个yml文件

  • application.yml:主配置文件,可以设置使用哪一个平台的信
# 设置到底运行的是哪一个平台的配置文件
spring:
  profiles:
    active :
      dev
  • 第二个配置文件 application-dev.yml,设置本地运行平台的配置信息
# 本地运行配置文件
file:
  path:
    C:\\Users\\30283\\Pictures\\picture\\
  •  第三个配置文件 application-run.yml,设置Linux运行平台的配置信息

# Linux运行环境配置

#文件路径 是自定义的路径
file:
  path:
    root\\save
@Controller
public class Choose {

    @Value("${file.path}")//读取配置文件信息 看运行的是一个配合文件信息
    private String choose;
    @RequestMapping("/choose")
    @ResponseBody
    public String choose() {
        return choose;
    }
}

在application.yml中选择dev时,运行本地配置文件 

 在application.yml中选择run时,运行linux配置文件

第二步:让文件地址可以变化

第三步:让文件类型可以变化

获取原来的文件名称,截取类型,通过UUID构建新的文件名称

@Controller
@Slf4j
public class UploadServlet {
    @Value("${file.path}")//读取配置文件信息 看运行的是哪一个配合文件信息 获取文件上传的目录
    private String dir;

    @ResponseBody
    @PostMapping("/uploadservlet")
    public String upload(@RequestPart("filename") MultipartFile file) {
        //得到源文件名称
        String filename = file.getOriginalFilename();
        log.info(filename);
        //截取得到文件类型
        String style = filename.substring(filename.lastIndexOf("."));
        log.info(style);
        //根据UUID 生成一个不重复的数字 拼接为新的文件名
        filename = dir + UUID.randomUUID().toString() + filename + style;
        log.info(filename);
        try {
            file.transferTo(new File(filename));//生成新文件 并拷贝内容
        } catch (IOException e) {
            e.printStackTrace();
            log.error("上传失败");
            return "上传失败";
        }
        return "上传成功";
    }
}

获取cookie

servlet中创建cookie,并获取cookie

@WebServlet("/setcookie")
public class SetCookie extends HttpServlet {

    /**
     * 给服务器返回一个Cookie
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");

        Cookie cookie = new Cookie("username", "张三");
        cookie.setMaxAge(60 * 60 );//设置cookie的存储时间
        resp.addCookie(cookie);//给浏览器返回cookie
        resp.getWriter().write("cookie创建成功");
    }
}
@WebServlet("/getcookie")
public class GetCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取服务器传递的Cookie
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        Cookie[] cookies = req.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                System.out.println(cookies[i].getName());
                if (cookies[i].getName().equals("username"))
                    resp.getWriter().write("username= " + cookies[i].getValue());
            }
        }
    }
}

SpringMVC中,创建Cookie的方式和servlet一样,通过HttpServletRequest类的方法实现

获取Cookie,有两种方式(1)在控制器中通过注解@CookieValue(键值名),获取指定某个cookie。(2)通过HttpServletRequest中的getcookies方法获取cookie数组,然后迭代里面的每一个cookie键值对。

(1)、SpringMVC项目的每一个方法,隐藏了两个参数

HttpServletRequest request, HttpServletResponse response
@Controller
public class GetCookie {
    @RequestMapping("/getcookie")
    @ResponseBody
    public String getCookie(HttpServletRequest request, HttpServletResponse response) {
        String name="username";
        String value=null;
        Cookie[]cookies=request.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            if(cookies[i].getName().equals("username")){
                value=cookies[i].getValue();
                break;
            }
        }
        if(value==null)
            return null;
        return name+value;
    }
}

(2)、在控制器中通过注解@CookieValue(键值名),获取指定某个cookie

@Controller
public class CookieInfo {
    @ResponseBody
    @RequestMapping("/getCookieByName")
    public String getCookie(@CookieValue("username") String value) {
        //value存放 cookie名称是username 对应的value值
        return "username= " + value;
    }
}

获取Session

1、SpringMVC创建session和servlet是一样的

@Controller
public class SetSession {
    @RequestMapping("/setsession")
    @ResponseBody
    //创建Session
    public String SetSession(HttpServletRequest request) {
        HttpSession session = request.getSession(true);//参数为true,如果不存在session,可以创建session
        if (session != null) {
            session.setAttribute("username", "张三");
            return "创建成功";
        }
        return "失败";
    }
}

 获取Session,有两种方式(1)在控制器中通过注解@SessionAttribute,获取指定某个Session。(2)通过HttpServletRequest中的方法获取

(1)、通过HttpServletRequest中的方法获取

@Controller
public class GetSession {
    @ResponseBody
    @RequestMapping("/getsession")
    public String getSession(HttpServletRequest request) {
        HttpSession session = request.getSession(false);//在会话不存在时,不可以重写建立会话
        if (session != null && session.getAttribute("username") != null) {
            return (String) session.getAttribute("username");
        }
        return null;
    }
}

(2)、在控制器中通过注解@SessionAttribute,获取Session

@Controller
public class GetSession {
    @ResponseBody
    @RequestMapping("/getsession")
    public String getSession(@SessionAttribute(value = "username")String value) {
        //将Session中 key是username 对应的value赋值给变量

        //required 默认为true 表示key是username 的键值对一定存在,如果真的不存在,会报错
        //required 为false,表示key是username 的键值对不一定存在,如果真的不存在,不会报错
        return value;
    }
}
required参数 默认为true 表示key是username 的键值对一定存在,如果真的不存在,会报错

当 key为username的 键值对并不存在,报错

@Controller
public class GetSession {
    @ResponseBody
    @RequestMapping("/getsession")
    public String getSession(@SessionAttribute(value = "username",required = false)String value) {
        //将Session中 key是username 对应的value赋值给变量

        //required 默认为true 表示key是username 的键值对一定存在,如果真的不存在,会报错
        //required 为false,表示key是username 的键值对不一定存在,如果真的不存在,不会报错
        return value;
    }
}

当 key为username的 键值对并不存在,不会报错,只是没有显示结果

获取Header

1、创建Header

@Controller
public class SetHeader {
    @ResponseBody
    @RequestMapping("/setheader")
    public void setHeader(HttpServletRequest request, HttpServletResponse response) {
        response.setCharacterEncoding("utf-8");
        response.setHeader("SetName", "zhangsan");
    }
}

2、 获取Header,有两种方式(1)在控制器中通过注解@RequestHeader,获取指定某个Header。(2)通过HttpServletRequest中的方法获取

(1)、通过HttpServletRequest中的方法获取

@Controller
public class GetHeader {
    @RequestMapping("/getheader")
    @ResponseBody
    public String getHeader(HttpServletRequest request) {
        String value = request.getHeader("Accept-Encoding");
    
        return "Accept-Encoding : " + value ;
    }
}

 (2)、通过@RequestHeader注解获取

 requried参数起到和之前一样的作用

@Controller
public class GetHeader {
    @RequestMapping("/getheader")
    @ResponseBody
    public String getHeader(@RequestHeader(value = "Date",required = false) String value) {
        return value;
    }
}

返回数据

返回静态页面

返回json数据 

@Controller
public class SetStudent {
    @ResponseBody
    @RequestMapping("/setstudent")
    public Student student() {
        Student student = new Student();
        student.setAge(10);
        student.setName("张三");
        student.setId(2);
        return student;
    }
}

请求转发

在java后端中,实现页面跳转的两种方式:请求转发和请求重定向

1、在servlet时期,实现请求转发:

@WebServlet("/login")
public class Login extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("user_name");
        String password = req.getParameter("user_password");
        if (username != null && password != null && username.equals("张三") && password.equals("123"))
            req.getRequestDispatcher("success.html").forward(req, resp);
    }
}

 2、在SpringMVC,在使用HttpServletRequest类的方法之外,还直接使用关键字forward实现请求转发

@Controller
public class Forward {
    @RequestMapping("/login")
    public String print() {
        return "forward:/success.html";
    }
}

请求重定向

1、servlet中实现:

@WebServlet("/redirect")
public class Redirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("user_name");
        String password = req.getParameter("user_password");
        if (username != null && password != null && username.equals("张三") && password.equals("123"))
            resp.sendRedirect("success.html");
    }
}

 2、spring MVC还可以使用关键字redirect实现

@Controller
public class Redirect {
    @RequestMapping("/redirect")
    public String reDirect() {
        return "redirect:/success.html";
    }
}

 请求转发和请求重定向的区别

 也就是 请求转发,客户端只会有一次请求,内部页面跳转由服务器进行,因为只有一次请求,涉及到的资源是共享的,要求资源都在同一个目录之下,否则无法访问到某些资源

请求重定向,客户端会有多次请求,内部页面跳转由客户端进行,因为有多次请求,涉及到的资源是不共享的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值