12-Spring MVC程序开发

目录

1.什么是Spring MVC?

1.1.MVC定义

1.1.1.Model(模型)

1.1.2.View(视图)

1.1.3.Controller(控制器)

1.2.MVC和Spring MVC的关系

2.为什么要学Spring MVC?

3.怎么学Spring MVC?

3.1.Spring MVC创建和连接

3.1.1.创建Spring MVC项目

3.1.2.实现用户和程序的连接

①使用@RequestMapping("/xxx")注解(2种用法)

②@GetMapping("/xxx")注解

③@PostMapping("/xxx")注解

--->PS:Idea社区版Spring Boot热部署

3.2.获取参数

3.2.1.获取单个参数

3.2.2.获取多个参数

3.2.3.获取对象

3.2.4.获取表单参数/获取多个参数(非对象)

--->扩展:后端参数重命名(后端参数映射)

3.2.5.@RequestBody获取JSON对象

--->PS:验证是否是标准的JSON字符串->浏览器搜索jsonview(json视图的转换工具)或json格式化

3.2.6.@PathVariable通过URL地址获取参数

3.2.7.@RequestPart获取前端传递的文件

3.2.8.获取前端比较特殊的一类参数Cookie/Session/header

3.3.返回数据

3.3.1.返回静态页面

3.3.2.使用@ResponseBody注解返回非静态页面的数据text/html

3.3.3.返回JSON对象

3.3.4.请求转发和请求重定向

--->PS:forward(请求转发)和 redirect(请求重定向)的区别:


1.什么是Spring MVC?

Spring MVC是基于MVC设计模式并在Servlet API基础上实现的一个Web框架

Web框架是基于http协议(里面会封装好Request,Response对象)。

web项目是指服务端部署在服务器上,客户端使用浏览器通过网络传输进行访问获取数据的项目。

Spring MVC也是用来去写后端接口的,实现前后端分离时接口的一个数据提供。

它从一开始就包含在Spring框架中(Spring是一个很大的体系,Spring MVC只是属于Spring体系中的一个Web模块,比Spring Boot早很多,但Spring Boot比Spring MVC名气大~介绍项目时多说为Spring Boot)。

它的正式名称Spring Web MVC来自其源模块的名称(spring-webmvc)。

有2种创建方式:①基于Spring创建(不用了);②基于Spring Boot创建。

1.1.MVC定义

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

1.1.1.Model(模型)

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

1.1.2.View(视图)

是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。

1.1.3.Controller(控制器)

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

1.2.MVC和Spring MVC的关系

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

二者之间的关系,就像是IoC(控制反转-思想)和DI(依赖注入-具体实现)之间的关系。

2.为什么要学Spring MVC?

目前几乎企业里所有的Java项目都是基于Spring/Spring Boot的,而Spring Boot是Spring的脚手架,Spring MVC是Spring的核心模块,Spring MVC是Spring/Spring Boot项目的基础。因此现在市面上绝大部分的Java项目约等于Spring MVC项目,这就是为什么要学的原因。

3.怎么学Spring MVC?

目标:需要掌握3个功能:

①连接功能:当用户通过浏览器输入一个url地址,将用户(浏览器)和Java程序连接起来,也就是访问一个url地址能够调用匹配到Spring程序中的某个方法。

②获取参数功能:用户访问的时候会带一些参数(用户名,密码等),在程序中要想办法获取到前端的请求参数。

③返回数据功能:执行了业务逻辑数据处理之后,要把服务器端程序执行的结果返回给前端(用户)。

这样就实现了用户与服务器的一次交互。

3.1.Spring MVC创建和连接

3.1.1.创建Spring MVC项目

当Spring MVC使用Spring Boot的方式创建时,二者的创建项目步骤相同。

在创建Spring Boot项目时勾选上Spring Web模块就相当于基于Spring Boot创建了Spring MVC项目。

  • 大多数场景下:Spring Boot >= Spring Web == Spring MVC。
  • 介绍时若说SSM项目->即Spring Boot + Spring MVC + Mybatis。
  • 若说SM项目->即Spring Boot + Mybatis。

3.1.2.实现用户和程序的连接

①使用@RequestMapping("/xxx")注解(2种用法)

@RequestMapping("/xxx")用来注册接口的路由映射。

路由映射:当用户访问一个url("/xxx"前面一定要加"/",url在Windows上不区分大小写,在Linux上区分大小写。那么写时一律小写,若有多个单词之间用"-"分割)时,将用户的请求对应到程序中某个类的某个方法的过程)

@RequestMapping既可修饰类,也可修饰方法,不可单独修饰类,可直接修饰方法。

当修饰类和方法时,访问的地址是类+方法。

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

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/sayhi") //路由映射(用户和程序的连接)
    @ResponseBody //当前方法返回的是一个非静态页面的数据,可以放在方法上也可以放在类上
    public String sayHi() {
        return "Hello, Spring MVC";
    }

}

localhost表示本地回环地址(127.0.0.1),它能访问当前电脑,访问不了云服务器(在公网/外网)。

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

@Controller
@ResponseBody //当前类返回的是一个非静态页面的数据,可以放在方法上也可以放在类上
public class UserController {

    @RequestMapping("/sayhi") //路由映射(用户和程序的连接)
    public String sayHi() {
        return "Hello, Spring MVC";
    }

}

默认情况下(不设置method),@RequestMapping既支持GET方式请求(默认的),又支持POST方式请求......

用Fiddler抓包来看一下请求和返回的格式:

 通过POST方式是否也可以呢?利用Postman来模拟尝试一下:

需求:让/user/sayhi方法只能支持GET方式请求,不能支持POST方式请求。

@RequestMapping中包含很多参数:

枚举

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {
    //表示此方法只支持GET类型的请求
    @RequestMapping(value = "/sayhi", method = RequestMethod.GET)
    @ResponseBody
    public String sayHi() {
        return "Hello, Spring MVC";
    }
}

 使用Postman模拟POST请求:

②@GetMapping("/xxx")注解

 表示此方法只支持GET类型的请求。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {
    //表示此方法只支持GET类型的请求
    @GetMapping("/sayhi")
    @ResponseBody
    public String sayHi2() {
        return "Hello, Spring MVC2";
    }
}

 浏览器默认是GET请求。

③@PostMapping("/xxx")注解

表示此方法只支持POST类型的请求。

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

@Controller
@RequestMapping("/user")
public class UserController {
    //表示此方法只支持POST类型的请求
    @PostMapping("/sayhi")
    @ResponseBody
    public String sayHi3() {
        return "Hello, Spring MVC3";
    }
}

小结:

GET请求的3种写法:

@RequestMapping("/sayhi")
@RequestMapping(value = "/sayhi", method = RequestMethod.GET)
@GetMapping("/sayhi")
POST请求的2种写法:
@RequestMapping(value = "/sayhi", method = RequestMethod.POST)
@PostMapping("/sayhi")

--->PS:Idea社区版Spring Boot热部署

当项目中代码发生变动后,Idea会自动监测到(3s左右),进而帮我们重启运行代码以达到自动更新的目的。我们自己不用管。

Step1:添加热部署框架支持spring-boot-devtools

作用域:只在运行阶段起作用。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<scope>runtime</scope>
	<optional>true</optional>
</dependency>

①创建项目时就将其加进来;

②在原项目中右键Generate->Edit Starters的方式添加。

Step2:设置开启项目自动编译

设置当前项目:

 设置新项目:

Step3:开启运行中热部署

老版本:

 新版本:2021.2之后的idea版本

Step4:使用debug运行,不要用run。

3.2.获取参数

参数获取都是包装类型(可以接收null),不会因为没有传递参数而报错,不会出现500的情况。

不可以是基本类型,会报错。

3.2.1.获取单个参数

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

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    /**
     * 接收单个参数
     * 
     * @param name
     * @return
     */
    @RequestMapping("/show-name")
    public String showName(String name) {
        return "姓名:" + name;
    }
}

不用类型转换。

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

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/shownum")
    public String showNumber(Integer number) {
        return "数字:" + number;
    }
}

3.2.2.获取多个参数

import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/login")
    public boolean islogin(String name, String password) {
        boolean result = false;
        //非空效验
//        if(name != null && !name.equals("") && password != null && !password.equals("")) {
//
//        }
        if(StringUtils.hasLength(name) && StringUtils.hasLength(password) && name.equals("admin") && password.equals("admin")) {
             return true;
        }
        return result;
    }
}

3.2.3.获取对象

Spring MVC可以自动实现参数对象的赋值,框架会帮助将此对象的所有属性进行填充。

定义实体类:

import lombok.Data;

@Data //一系列方法的组合
public class UserInfo {
    private int id;
    private String name;
    private int age;
    private String password;
    private String photo;
}
import com.example.demo.model.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/reg")
    public UserInfo reg(UserInfo userInfo) {
        return userInfo;
    }
}

 POST格式也是一样:

3.2.4.获取表单参数/获取多个参数(非对象)

和3.2.2.获取多个参数一样,注意:当有多个参数,前后端进行参数匹配时,是以参数的名称来进行匹配的,因此参数的位置是不影响后端获取参数的结果的。

--->扩展:后端参数重命名(后端参数映射)

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个time 给后端,⽽后端⼜是由 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值

@RequestParam("xxx") 类型 yyy -> 将前端的xxx重命名为后端的yyy。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/login2")
    public String login2(@RequestParam("username") String name, String password) {
        return "用户名:" + name + " | 密码:" + password;
    }
}

3.2.5.@RequestBody获取JSON对象

之前的Postman在传递JSON对象时:

--->PS:验证是否是标准的JSON字符串->浏览器搜索jsonview(json视图的转换工具)或json格式化

得不到JSON对象。 so~要用@RequestBody获取JSON对象。

import com.example.demo.model.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/reg")
    public UserInfo reg(@RequestBody UserInfo userInfo) {
        return userInfo;
    }
}

3.2.6.@PathVariable通过URL地址获取参数

出现在传统网站里,为了提高搜索(某个内容比如json)排名权限,在url中存在一次/多次(该内容如json)。这种方式比在url中以"?"之后的传参要有效得多。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    @RequestMapping("/hero/{name}/{password}")
    public String  heroName(@PathVariable String name, @PathVariable String password) {
        return name+password;
    }
}

3.2.7.@RequestPart获取前端传递的文件

文件可以是任意类型,mp3,mp4,img......(图片最多)

关键实现步骤:

1).接收前端传递的文件:

@RequestPart("filename")MultipartFile file
//@RequestPart("filename")从前端获取一个文件名为filename(必须与前端给的名字一致)的对象
//MultipartFile专门用来接收文件格式的对象,并将其赋值到变量file(名字由后端随便起)上

2).将前端传递过来的文件保存到本地(服务器端):

file.transferTo(new File(filePath));
//用MultipartFile这个对象提供的transferTo方法将文件保存到filePath(文件的完整路径,在配置文件中配置)这个目录下

注:如果上传的是文件,不要使用GET类型的请求方式,一定要使用POST类型的请求方式

虽然在Postman中GET和POST设置表单提交都可以成功,但在真实应用场景当用GET设置表单提交不一定成功。

规范来说:上传用POST,查询用GET。

  • GET加在URL中有长度限制,文件较大会上传不成功;
  • POST放在BODY中无长度限制。

谷歌浏览器无法上传文件,必须有一个前端的HTML页面才能上传。故使用Postman来验证。

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;

@Controller
@RequestMapping("/user")
@ResponseBody
@Slf4j
public class UserController {
    /**
     * 上传文件
     *
     * @param username
     * @param file
     * @return
     */
    @RequestMapping("/upfile")
    public boolean upFile(String username, @RequestPart("file")MultipartFile file) {
        boolean result = false;
        try {
            file.transferTo(new File("E:\\Users\\Data\\img.png")); //"E:\\Users\\Data\\img.png"是全路径;"img.png"是给起的名字
            result = true;
            log.info(username + ":上传图片成功!");
        } catch (IOException e) {
            System.out.println("图片上传失败!");
        }
        return result;
    }
}

使用Postman模拟请求上传图片:

图片上传成功。

缺点:

因为代码写死的,所以当继续上传另一张图片时,会覆盖掉原来的图片。

完善:

①将文件的目录放到配置文件中;

②每次生成一个不同的文件名(不能使用时间戳,要使用UUID,UUID每次获取时都不会重复,即使是同一时刻并发访问也不会存在问题,jdk底层已经帮我们实现好了)。

# 图片的保存路径
file:
  path: E:/Users/Data/

# 注意:
# 表示在Data文件夹下
# E:/Users/Data/ 

# 表示在Users文件夹下,名称为Data
# E:/Users/Data
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Controller
@RequestMapping("/user")
@ResponseBody
@Slf4j
public class UserController {
    @Value("${file.path}")
    private String filePath; //从配置文件中获取图片的上传路径

    /**
     * 上传文件
     *
     * @param username
     * @param file
     * @return
     */
    @RequestMapping("/upfile")
    public boolean upFile(String username, @RequestPart("file") MultipartFile file) {
        boolean result = false;
        try {
            //得到原文件的名称和后缀
            String fileType = file.getOriginalFilename(); //获取文件的原生名字
            fileType = fileType.substring(fileType.lastIndexOf(".")); //获取文件的后缀/类型
            //文件保存的名称
            String fileName = UUID.randomUUID().toString() + fileType;
            file.transferTo(new File(filePath + fileName));
            result = true;
            log.info(username + ":上传图片成功!");
        } catch (IOException e) {
            System.out.println("图片上传失败!");
        }
        return result;
    }
}

 

当再次上传其他图片时,不会覆盖掉原图片:

3.2.8.获取前端比较特殊的一类参数Cookie/Session/header

①获取Cookie

方式1:(传统方式)通过HttpServletRequest getCookie获取(Servlet的获取方法)(获取所有的cookie)

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;


@Controller
@RequestMapping("/user")
@ResponseBody
@Slf4j
public class UserController {
    /**
     * 获取cookie方法1
     *
     * @param request
     */
   @RequestMapping("/getck")
    public void getCookie(HttpServletRequest request) {
       Cookie[] cookies = request.getCookies();
       log.info("cookie length:" + cookies.length);
       Arrays.stream(cookies).forEach(cookie -> {
           log.info(cookie.getName() + ":" + cookie.getValue());
       });
   }
}

在浏览器中模拟添加一个Cookie:

方式2:(简洁方式)通过@CookieValue注解获取(获取一个或少量的cookie值)

@CookieValue("CookieName") String CookieValue
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    /**
     * 获取cookie方法2
     * 
     * @param bite
     * @return
     */
    @RequestMapping("/getck2")
    public String getCookie2(@CookieValue("bite") String bite) { //将名为bite的cookie赋值给变量bite
        return bite;
    }
}

 

②获取header(请求头中的数据)

方式1:(传统方式)通过HttpServletRequest getHeader获取

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    /**
     * 获取header方法1
     * 
     * @param request
     * @return
     */
    @RequestMapping("/getheader")
    public String getHeader(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        return userAgent;
    }
}

方式2:(简洁方式)通过@RequestHeader注解获取

@RequestHeader("headerName") String headerValue
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
    /**
     * 获取header方法2
     * 
     * @param userAgent
     * @return
     */
    @RequestMapping("/getua")
    public String getUA(@RequestHeader("User-Agent") String userAgent) {
        return userAgent;
    }
}

③存储和获取Session(非常常用)

Session存储和Servlet类似,是使用HttpServletRequest中获取的。

设置Session:

//定义全局的session key
private final String SESSION_KEY = "SESSION_KEY";

/**
* 设置session
*
* @param request
* @return
*/
@RequestMapping("/setsess")
public boolean setSession(HttpServletRequest request) {
    boolean result = false;
    //得到session对象
    try {
       HttpSession session = request.getSession(true);
       session.setAttribute(SESSION_KEY, "Java");
       result = true;
    } catch (Exception e) {
       log.info("出现了异常:" + e.getMessage());
    }
    return result;
}

获取Session方式1:传统Servlet方式

/**
* 获取Session方式1
*
* @param request
* @return
*/
@RequestMapping("/getsess")
public String getSession(HttpServletRequest request) {
    String result = "";
    //得到session,如果存在就查询session中的值,否则返回空
    HttpSession session = request.getSession(false); //false:如果没有session就不用创建session对象
    if(session != null && session.getAttribute(SESSION_KEY) != null) {
        result = (String) session.getAttribute(SESSION_KEY);
    }
    return result;
}

获取Session方式2:(简洁方式)通过@SessionAttribute注解获取

2个都可以:(建议设置name)

@SessionAttribute(required = false, name = "SESSION_KEY") String data
@SessionAttribute(required = false, value = "SESSION_KEY") String data
/**
* 获取Session方式2
*
* @param data
* @return
*/
@RequestMapping("/getsess2")
public String getSession2(@SessionAttribute(required = false, name = "SESSION_KEY") String data) { //建议设置为false,如果不设置会默认为true,此时如果没有session也会弄到
    return data;
}

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/user")
@ResponseBody
@Slf4j
public class UserController {
    //定义全局的session key
    private final String SESSION_KEY = "SESSION_KEY";

    /**
     * 设置session
     *
     * @param request
     * @return
     */
    @RequestMapping("/setsess")
    public boolean setSession(HttpServletRequest request) {
        boolean result = false;
        //得到session对象
        try {
            HttpSession session = request.getSession(true);
            session.setAttribute(SESSION_KEY, "Java");
            result = true;
        } catch (Exception e) {
            log.info("出现了异常:" + e.getMessage());
        }
        return result;
    }

    /**
     * 获取Session方式2
     *
     * @param data
     * @return
     */
    @RequestMapping("/getsess2")
    public String getSession2(@SessionAttribute(required = false, name = "SESSION_KEY") String data) {
        return data;
    }
}

3.3.返回数据

默认情况下,无论是Spring Boot还是Spring MVC,返回的都是视图(xxx.html),而现在都是前后端分离的,后端只需要返回给前端数据即可,此时就需要使用@ResponseBody注解了。

3.3.1.返回静态页面

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1 style="color:red;">Hello, index.html.</h1>
</body>
</html>
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ResponseController {
    @RequestMapping("/index")
    public String getIndex() {
        return "index.html";
    }
}

3.3.2.使用@ResponseBody注解返回非静态页面的数据text/html

@ResponseBody:可以放在方法上也可以放在类上,表示当前方法/类中的所有方法返回的是一个非静态页面的数据。

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

@Controller
@ResponseBody // 表示当前类中的所有方法返回的是一个非静态页面的数据。
public class ResponseController {
    @RequestMapping("/index")
//    @ResponseBody  // 表示当前方法返回的是一个非静态页面的数据。
    public String getIndex() {
        return "index.html";
    }
}

一种更简单的写法:使用@RestController注解代替@Controller注解和@ResponseBody注解。

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

@RestController
public class ResponseController {
    @RequestMapping("/index")
    public String getIndex() {
        return "index.html";
    }
}

练习:实现计算器功能。

可使⽤ postman 传递参数,或使⽤ form 表单的⽅式提交参数。

前端⻚⾯:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
             content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算器示例</title>
</head>
<body>
<form action="calc" method="post">
    <h1>计算器</h1>
     数字1:<input name="num1" type="text"><br>
     数字2:<input name="num2" type="text"><br>
    <input type="submit" value=" 点击相加 ">
</form>
</body>
</html>

Controller代码:

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

@RestController
public class CalcController {
    @RequestMapping("/calc")
    public String calc(Integer num1, Integer num2) {
        return "<h1>结果为:" + (num1 + num2) + "</h1>" + "<p><a href='javascript:history.go(-1);'>返回上一步</a>"; //history.go(-1)表示回退,回到上一步
    }
}

 

 

3.3.3.返回JSON对象

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;

@Controller
@RequestMapping("/json")
@ResponseBody
public class JsonController {
    @RequestMapping("/index")
    public HashMap<String, String> ReturnJson() {
        HashMap<String, String> map = new HashMap<>();
        map.put("Java", "Java Value");
        map.put("MySQL", "MySQL Value");
        map.put("Redis", "Redis Value");
        return map;
    }
}

练习:实现登录功能,前端使⽤ ajax,后端返回 json 给前端。 

后端代码:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;

@Controller
@RequestMapping("/json")
@ResponseBody
public class JsonController {
     @RequestMapping(value = "/login")
     @ResponseBody
     public HashMap<String, Object> login(String username, String password) {
         HashMap<String, Object> res = new HashMap<>();
         int succ = 200;
         if(username != null && password != null && username.equals("admin") && password.equals("admin")) {
             res.put("msg", "登录成功");
         } else {
             res.put("msg", "登录失败");
         }
         res.put("succ", succ);
         return res;
     }
}

前端代码:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="js/jquery-1.9.1.min.js"></script>
    <title>Document</title>
    <script>
        function mysub() {
            var username = jQuery("#username").val();
            var password = jQuery("#password").val();
            jQuery.getJSON("/user/login",
                {
                    "username" : username,
                    "password" : password
                },
                function (result) {
                if(result.succ == 200) {
                    alert("返回结果:" + result.msg);
                } else {
                    alert("操作失败,请重试。");
                }
            });
        }
    </script>
</head>
<body>
<div style="text-align: center;">
    <h1>登录</h1>
    ⽤户:<input id="username">
    <br>
    密码:<input id="password" type="password">
    <br>
    <input type="button" value=" 提交 " onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
</div>
</body>
</html>

3.3.4.请求转发和请求重定向

return不但可以返回一个视图,还可以实现跳转,Spring MVC有2种跳转方式:

①请求转发:forward(事多)

地址不变。

实现方法1:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>Hello, hello.html.</h1>
</body>
</html>
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ResponseController {
    /**
     * 请求转发的实现方法1
     * 
     * @return
     */
    @RequestMapping("/fw")
    public Object forward() {
        return "forward:hello.html";
    }
}

实现方法2:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class ResponseController {
    /**
     * 请求转发的实现方法2
     *
     * @return
     */
    @RequestMapping("/fw2")
    public void forward2(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {
        request.getRequestDispatcher("hello.html").forward(request, response);
    }
}

 ②请求重定向:redirect(事少)

地址会变。

实现方法1:

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

@Controller
public class ResponseController {
    /**
     * 请求重定向的实现方法1
     * 
     * @return
     */
    @RequestMapping("rt")
    public Object redirect() {
        return "redirect:hello.html";
    }
}

 实现方法2:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class ResponseController {
    /**
     * 请求重定向的实现方法2
     *
     * @return
     */
    @RequestMapping("rt2")
    public void redirect2(HttpServletResponse response) throws IOException {
       response.sendRedirect("hello.html");
    }
}

--->PS:forward(请求转发)和 redirect(请求重定向)的区别:

举例来说:

你告诉你妈妈,你想吃辣条:

  • 如果你妈妈说好,我帮你去买,这就是 forward 请求转发。
  • 如果你妈妈让你⾃⼰去买,那么就是 redirect 请求重定向。

forward 和 redirect 具体区别如下:

  1. 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)是服务器端帮转发。
  2. 请求重定向地址发⽣变化;请求转发地址不发⽣变化。
  3. 请求重定向与直接访问新地址效果⼀致,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值