《JavaEE进阶》----5.<SpringMVC②剩余基本操作(Cookie&Session&Header&响应)>

Cookie和Session简介。

Spring MVC的

2.请求

Cookie的设置和两种获取方式

Session的设置和三种获取方式。

3.响应

1.返回静态页面

2.返回数据

3.返回HTML片段

4.返回JSON

5.设置状态码

6.设置header

三、(接上文)SpringMVC剩余基本操作

3.2postman请求

3.2.10 获取Cookie和Session

1.理解Cookie

我们知道HTTP协议自身是"无状态"协议。

"无状态" 的含义指的是:

默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信和下次通信之间没有直接的联系.

实际开发中,我们很多时候需要知道请求之间的关联关系。

例如登陆网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登陆过了.

当用户输入用户名和密码点击登录后,服务器响应,这时候登陆成功后,服务器会给用户一个"令牌",这样下次用户再访问,就会带上"令牌"。服务器就知道这个用户已经登陆过了。

"令牌" 通常就存储在 Cookie 字段中.

此时在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是 Session 机制所做的工作.

2.理解Session

此时在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是 Session 机制所做的工作.

Session就是会话的意思,比如10个浏览器请求同一个服务器(同样的进程)。那么就会产生10个会话。这10个会话,服务器会通过Session来分辨出会话是哪个浏览器请求的。

服务器同⼀时刻收到的请求是很多的.服务器需要清楚的区分每个请求是从属于哪个用户,也就是属于哪个会话,就需要在服务器这边记录每个会话以及与用户的信息的对应关系. Session是服务器为了保存用户信息而创建的⼀个特殊的对象.

Session的本质就是⼀个 "哈希表",存储了⼀些键值对结构.Key就是SessionID,Value就是用户信息(用户信息可以根据需求灵活设计)。

SessionID就是由服务器生成的,"唯一性"字符。从Session机制角度看来,这个唯一性字符就是SessionID。如果站在登录流程中看待,也可以把这个唯一性字符称作"token"。

3.Cookie 和 Session之间的关系。(举例)


举一个生活中的例子,新生入学,学校会收录学生信息存储在教务系统,并为每一个学生设定学号

存储学生信息示例如下:

001 张三 18 计科1班

002 李四 19 计科1班

003 王五 18 计科1班

这里的信息就相当于Session


而学校存储信息之后,会给学生发学生证。

出入校园,使用学生证来证明学生身份。

这里的学生证就相当于Cookie

注意:

学生证**(Cookie):** 是可以造假。

教务系统信息**(Session)** :一定是真的

4.Cookie和session的区别

5.获取Cookie (两种方式)

①传统写法(可获取所有Cookie)
java 复制代码
@RestController
@RequestMapping("/request")
public class RequestController {
    /**
     * 传统方法获取Cookie
     * 每个方法都内置了HttpServletRequest request/HttpServletResponse response对象
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();//通过这种方式可以获取Cookie

        //我们使用lambda表达式的方式来打印Cookie。这种写法可以先了解一下。
//        Arrays.stream(cookies).forEach(x->{
//            System.out.println(x.getName() + ":" + x.getValue());
//        });
        //等价于使用foreach循环来打印Cookie
        for (Cookie c: cookies){
            System.out.println(c.getName()+":"+c.getValue());
        }
        return "获取Cookie成功!!!";
    }
}

注意,如果Cookie为空,会报异常。因此写法如下。

java 复制代码
    @RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();//通过这种方式可以获取Cookie
//使用foreach循环来打印Cookie
        if(cookies != null){
            for (Cookie c: cookies){
                System.out.println(c.getName()+":"+c.getValue());
            }
            return "获取Cookie成功!!!";
        }
        return "Cookie为空!";
    }

运行结果

当我们添加Cookie之后,刷新一下

Cookie也被打印在控制台上。从这里也可以看出,Cookie是可以造假,除了通过浏览器造假,通过Postman也是可以造假的。

②Spring Boot写法(@CookieValue注解获取指定Cookie)

我们使用postman添加几个Cookie,当我们使用传统方式打印Cookie

我们得到了所有的Cookie。但是当我们用SpringBoot方式打印。我们只能通过注解

@CookieValue来或者指定key值的cookie。

java 复制代码
    @RequestMapping("getCookie2")
    public String getCookie2(@CookieValue("yang")String yang){
        return "yang:"+yang;
    }

因此使用这两种方法取决于你想要获取

全部Cookie还是

只获得某些Cookie

6.获取Session

①传统写法
java 复制代码
    @RequestMapping("setSession")
    public String setSession(HttpServletRequest request){
        HttpSession session = request.getSession();
        session.setAttribute("student","zzx");
        return "设置Session成功!";
    }

    @RequestMapping("getSession")
    public String getSession(HttpServletRequest request){
        HttpSession session = request.getSession();
//默认值为ture,如果Session为null,就创建一个空的Session
        String student = (String) session.getAttribute("student");
        return "登录用户:"+student;
    }

http://127.0.0.1:1208/request/setSession

http://127.0.0.1:1208/request/getSession

②SpringBoot写法()
I.直接使用内置对象HttpSession session获取Session。
java 复制代码
    @RequestMapping("getSession2")
    public String getSession(HttpSession session){
        String student = (String) session.getAttribute("student");
        return "登录用户:"+student;
    }
II.使用注解 (@SessionAttribute)
java 复制代码
    @RequestMapping("getSession3")
    public String getSession(@SessionAttribute("student")String student){
        return "登录用户:"+student;
    }

虽然这样写如下代码非常的简短,但是也有一个问题就是如果直接getSession。会报错

没有找到student这个类型。这是因为加了注解之后,这个参数就变成了必传参数,因此不能为空。

如何修改呢,如下: @SessionAttribute(value = "student",required = false)

java 复制代码
    @RequestMapping("getSession3")
    public String getSession(@SessionAttribute(value = "student",required = false)String student){
        return "登录用户:"+student;
    }

此时就不报错了。

3.2.11 获取Header

我们请求打印Header。中的 User-Agent 的信息。

它表示用的哪个客户端去请求的。

①传统方式

java 复制代码
    @RequestMapping("/getHeader")
    public String getHeader(HttpServletRequest request){
        String userAgent = request.getHeader("User-Agent");
        return "userAgent:"+userAgent;
    }

②SpringBoot方式(@RequestHeader注解)

java 复制代码
    @RequestMapping("/getHeader2")
    public String getHeader2(@RequestHeader("User-Agent")String userAgent){
        return "userAgent:"+userAgent;
    }

上图:当我们使用Postman请求。

上图:当我们使用浏览器请求。
我们只想获取Header信息中的其中的一个,使用SpringBoot方式很方便。

当我们想要获取多个内容,使用SpringBoot方式就需要写很多参数。

因此我们可以使用传统方式更加方便的获取。

请求完结。

3. 3响应:

在响应中,我们有以下操作:

1.返回静态页面

2.返回数据

3.返回HTML片段

4.返回JSON

5.设置响应头(状态码,编码或者其他header)

我们可以

使用Fiddler来查看请求和响应的数据

执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤⼾,也就是响应.

1.返回静态页面(页面)

首先要有一个静态页面,

创建前端页面index.html(注意路径)。

如果要访问的目录在静态目录static下面,还有其他目录,那么路径url中需要带上这个目录

java 复制代码
@Controller
@RequestMapping("/return")
public class ReturnController {
    @RequestMapping("/r1")
    public String r1(){
        return "/index.html";
    }
}

注意:

1.在SpringBoot中。@RequestMapping中的/是可以被省略的。而return中的/不能省略。

2.当我们想要访问静态页面时,我们需要把原先

@RestController注解改为@Controller

@RestController注解与@Controller的区别和联系

想要返回数据使用:@RestController

想要返回页面使用:@Controller

@RestController = @ResponseBody + @Controller

@Controller:告诉Spring帮我们管理哪些程序,默认返回的是页面

@ResponseBody:表示返回数据

我们看看注解@RestController的源码

java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

注解解释

@Target:表示注解的使用范围如上:ElementType.TYPE 表示注解只能修饰类

@Retention:表示注解的生命周期

我们看看注解@Controller的源码

java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

2.返回数据 @ResponseBody注解

源码

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}

表示返回数据。响应正文里面的内容。

这里区别@RequestBody:是请求正文里面的内容。接收JSON的时候我们经常用到。

它既可以修饰类,也可以修饰方法。

**修饰类:**表示该类所有的方法,返回的都是数据

**修饰方法:**表示该方法的返回都是数据。

示例:

java 复制代码
    @ResponseBody
    @RequestMapping("/r2")
    public String r2(){
        return "hello ,SpringMVC,我是返回的数据";
    }

ps:关于路径中是否有项目名&一个项目部署多个服务/部署多个项目

3.返回HTML片段(数据)

java 复制代码
    @ResponseBody
    @RequestMapping("/r3")
    public String r3(){
        return "<h1>hello ,SpringMVC,我是HTML片段</h1>";
    }

注意这里文本类型是html。

content-Type:text/html

无论返回的是页面,还是数据。content-Type类型都是html

如果让它返回JSON呢?请往下看。

ps:get和post的区别

get可以被缓存,get是幂等的。不管什么时候请求,得到响应是一样的。

post不可以被缓存。

4.返回JSON(对象,哈希表等键值对格式)

JSON通常也是表示对象,我们返回一个对象试试。

java 复制代码
    @ResponseBody
    @RequestMapping("/r4")
    public UserInfo r4(){
        UserInfo userInfo = new UserInfo();
        userInfo.setName("zzx");
        userInfo.setId(9);
        userInfo.setAge(18);
        return userInfo;
    }

如上如,我们返回对象成功返回了JSON类型的文本。

content-Type:application/json

java 复制代码
    @ResponseBody
    @RequestMapping("/r5")
    public Map<String,String> r5(){
        HashMap map = new HashMap<>();
        map.put("k1","v1");
        map.put("k2","v3");
        map.put("k3","v3");
        return map;
    }

content-Type:application/json

如上如,使用Map也成功返回了JSON类型的文本。

java 复制代码
    @RequestMapping("/r6")
    public String r6(){
        return "/a.js";
    }

content-Type:application/javascript

成功返回了页面a.js

java 复制代码
    @RequestMapping("/r7")
    public String r7(){
        return "/b.css";
    }

content-Type:text/css

成功返回了页面b.css

总结:

在SpringBoot中, content-Type 不需要我们自己设置。

会自动根据我们的返回的结果自行设置。

5.设置状态码(HttpServletResponse)

状态码的设置不影响页面的展示。

错误显示可以自定义的图。也有很多公共的页面格式。

java 复制代码
    @ResponseBody
    @RequestMapping("/r8")
    public String r8(HttpServletResponse response){
        response.setStatus(401);
        return "设置状态成功!";
    }

6.设置Header(了解)

Http响应报头也会向客户端传递⼀些附加信息,

比如服务程序的名称,请求的资源已移动到新地址等

如:Content-Type、Local等.

这些信息通过@RequestMapping注解的属性来实现

先来看@RequestMapping的源码:

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

简单了解一下它的属性:(了解就好,不用记)

**1.value:**指定映射的URL

下面这些属性更多的是对请求的限制

**2.method:**指定请求的method类型,如GET,POST等

**3.consumes:**指定处理请求(request)的提交内容类型(Content-Type),例如application/json、text/html;

**4.produces:**指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回

**5.Params:**指定request中必须包含某些参数值时,才让该方法处理

**6.headers:**指定request中必须包含某些指定的header值,才能让该方法处理请求

我们前面了解到,在Spring中,content-Type:的类型不需要我们自己设置,不过在工作中可能有时候还需要我们设置。

而且有些 Header 是自定义的。

什么都没写的时候,我们发现只有

这样的如

Content-Type:

Content-Length:

Data:

Keep-Alive:

Connection:

但是我们访问其他网站,就会发现会有许多。有些就是他们自定义的。

设置Content-Type(produce属性):

SpringBoot给我们默认的是 text/html 类型。要想我们自定义,我们就要用到

@RequestMapping的produce属性。下面是我们给它设置成json的代码:

java 复制代码
    @ResponseBody
    @RequestMapping(value = "/r9",produces = "application/json")
    public String r9(){
        return "自定义Header中的Content-Type成功!";
    }

那么我们返回的本身就不是json,如果不自定义,那么就是text/html

什么时候会使用这种情况呢?

比如当我们返回{"ok":1}这串数据,是json格式,但是Spring这里默认还是html。这样就可以会对前端造成一定的影响。不过现在前端框架也更新了,可以自动识别为json

通过这样我们也可以在后面写

@RequestMapping(value = "/r9",produces = "application/json;charset = utf-8")

因此也可以同步的设置编码。

自定义Header(HttpServletResponse)
java 复制代码
    @ResponseBody
    @RequestMapping(value = "/r10")
    public String r10(HttpServletResponse response){
        response.setHeader("myHeader","myHeaderValue");
        return "自定义Header成功!";
    }

这就多了一个

myHeader:myHeaderValue

对于SpringMVC来说,掌握了以上3个功能(建立链接+请求+响应)就相当于掌握了SpringMVC.

相关推荐
兩尛1 天前
Spring面试
java·spring·面试
Java中文社群1 天前
服务器被攻击!原因竟然是他?真没想到...
java·后端
Full Stack Developme1 天前
java.nio 包详解
java·python·nio
零千叶1 天前
【面试】Java JVM 调优面试手册
java·开发语言·jvm
代码充电宝1 天前
LeetCode 算法题【简单】290. 单词规律
java·算法·leetcode·职场和发展·哈希表
li3714908901 天前
nginx报400bad request 请求头过大异常处理
java·运维·nginx
摇滚侠1 天前
Spring Boot 项目, idea 控制台日志设置彩色
java·spring boot·intellij-idea
Aevget1 天前
「Java EE开发指南」用MyEclipse开发的EJB开发工具(二)
java·ide·java-ee·eclipse·myeclipse
黄昏晓x1 天前
C++----多态
java·jvm·c++
Brookty1 天前
【算法】前缀和
java·学习·算法·前缀和·动态规划