JavaEE-Spring Controller(服务器控制以及Controller的实现和配置)

Spring Controller


服务器控制

响应架构

Spring Boot 内集成了 Tomcat 服务器,也可以外接 Tomcat 服务器。通过控制层接收浏览器的 URL 请求进行操作并返回数据。

底层和浏览器的信息交互仍旧由 servlet 完成,服务器整体架构如下:

  • Server: Tomcat 最顶层容器,代表整个服务器。

    • Service:服务,对应不同的任务。

      • Connector:有多个,用来处理连接相关的事情,并提供 Socket 到 Request 和 Response 相关转化。

      • Container:只有一个,用于封装和管理 Servlet ,以及处理具体的 Request 请求。

启动过程

main 方法: 实例化 SpringApplication ,执行run方法

run方法:
配置属性、获取监听器,初始化输入参数、配置环境,输出banner 创建上下文、预处理上下文、刷新上下文、再刷新上下文:context

refreshApplicationContext方法:通过ServletWebServerFactory接口定义了getwebServer方法,通过其创建webServer并返回(创建时做了两件重要的事情:把Connector对象添加到tomcat中,配置引擎)【TomcatServletWebServerFactory是接口其中一个实现类】

TomcatwebServer类中,规定了Tomcat服务器的启动和关闭方法。

而tomcat的启动主要是实例化两个组件:Connector、Container


Controller 实现

Controller 类需要使用 @RestController 或 @Controller 注解标注。

  • @Controller:类中所有方法以 String 形式返回 classpath 路径下同名 html 页面。适用于 JSP/thymeleaf 等动态加载页面。

  • @RestController:类中所有方法以 Map/List 等形式返回 JSON 数据。适用于前后端分离开发。

P.S. @Controller 类中标注 @ResponseBody 的方法,可以起到和 @RestController 类相同的效果。

请求映射

  1. Controller 类中的方法使用 @RequestMapping 注解标注,就可以将指定 URL 请求映射到方法上处理。
@RequestMapping(value = "/hello", method = RequestMethod.GET)     // 参数为 URL 路径和请求方式
@RequestMapping("/hello")                                         // 默认接收所有请求方式

@GetMapping("/hello")                                             // 简写形式的 GET 请求
@PostMapping("/hello")                                            // 简写形式的 POST 请求

// 灵活映射
@RequestMapping("/?/hello")                                       // ? 匹配单字符
@RequestMapping("/*/hello")`:                                    // * 匹配任意数量字符
@RequestMapping("/**/hello")// ** 匹配任意数量目录
@RequestMapping("/{ID}/hello")`                                   // {} 自动读取 URL 路径动态参数Copy to clipboardErrorCopied
  1. Controller 类也可以通过 @RequestMapping 注解标注,表示路径下的 URL 请求在该类中寻找方法。
@Controller
@RequestMapping("/speak")
public class SpeakController{
    @GetMapping("/hello")
    public String hello(){ return "hello"; } 
}Copy to clipboardErrorCopied

GET 请求参数

GET 请求参数直接附着在 URL 中。对于请求 /test?username=mrjoker&password=123456 ,Controller 方法有以下几种方式接收:

  1. 直接获取参数
@RequestMapping("/test")
public String test(String username, String password){
    return username + password;
}Copy to clipboardErrorCopied
  1. 通过 HttpServletRequest 类来获取参数
@RequestMapping("/test")
public String test(HttpServletRequest request){
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    return username + password;
}Copy to clipboardErrorCopied
  1. 通过自定义对象来获取参数
@RequestMapping("/test")
public String test(User user){
    String username = user.getUsername();
    String password = user.getPassword();
    return username + password;
}Copy to clipboardErrorCopied
  1. 通过 RequestParam 注解来获取参数,实参值赋给形参。
@RequestMapping("/test")
public String test(@RequestParam(value="username",required = false, defaultValue ="mrjoker") String s1, @RequestParam("password") String s2){
    return s1 + s2;
}Copy to clipboardErrorCopied
  1. 通过 PathVariable 注解来动态获取参数,参数直接附着在 URL 中。
@RequestMapping("/test/{username}/{password}")
public String test(@PathVariable("username") String s1, @PathVariable("password") String s2){
    return s1 + s2;
}Copy to clipboardErrorCopied
  1. 通过 ModelAttribute 注解来获取其他方法返回值作为参数,被注释方法会在此 controller 中每个方法执行前被执行。
@Controller 
public class HelloWorldController { 
    @ModelAttribute 
    public void populateModel(@RequestParam String abc, Model model) { 
        model.addAttribute("attributeName", abc); 
    } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld() { 
       return "helloWorld"; 
    } 
}Copy to clipboardErrorCopied

POST 请求参数

POST 请求请求参数放置在请求体中,有以下两种格式:

  • Form Data 格式

请求的 Content-Type 为 application/x-www-form-urlencoded

示例:username=mrjoker&password=123456

  • Request Payload 格式

请求的 Content-Type 为 application/json 或者 multipart/form-data

示例:{"username":"mrjoker", "password":"123456"}

  1. AJAX 提交 POST 请求默认使用 Form Data 格式,Spring MVC 会自动解析到对应的 bean 中并获取参数。
// 逐个参数接收
@RequestMapping(value="/test", method=RequestMethod.POST)
private String test(@RequestParam("username") String username, @RequestParam("password") String password){
    return username + password;
}

// 解析为整体接收
@RequestMapping(value="/test", method=RequestMethod.POST)
private String test(User user){
    return user.getUsername() + user.getPassword();
}Copy to clipboardErrorCopied
  1. Vue 提交 POST 请求默认使用 Request Payload 格式,Spring MVC 接收时必须进行处理:

    • 前端解决方案: axios 库可以使用 qs 库将 json 对象转化为 Form Data 格式。
    • 后端解决方案: Spring Boot 在请求参数上加 @RequestBody 注解,将请求正文解析到对应的 bean 中获取参数。

@RequestBody 可以直接以 String 接收前端传过来的 json 数据,也可以用对象自动解析前端传过来的 json 数据。对象里定义 List 属性,可用来接收多条 json 数据。

// String 形式接收
@RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(@RequestBody String user) {
    JSONObject userJson = JSON.parseObject(user);
    String username = userJson.getString("username");
    String password = userJson.getString("password");
    return username + password;
}

// 解析为对象接收
@RequestMapping(value = "/test", method = RequestMethod.POST)
public String updateClusterIdByClientAndQueue(@RequestBody User user) {
    return user.getUsername() + user.getPassword();
}Copy to clipboardErrorCopied

一个请求可以有多个 @RequestParam,但只能有一个 @RequestBody。 URL 内含有参数时,两者可以同时使用。

请求转发和重定向

  1. 请求转发(forward)

    客户端(浏览器)向服务器 A 发送一个 URL 请求,服务器 A 会向另一台服务器 B 获取资源并将此资源响应给浏览器。浏览器的 URL 地址仍然是 A 。

  2. 重定向(Redirect)

    客户端(浏览器)向服务器 A 发送一个 URL 请求,服务器 A 告知浏览器资源在服务器 B,浏览器会重新发送请求到服务器 B。浏览器的 URL 地址切换为 B。

// 请求转发
@RequestMapping("/test1")
public String test1(){
    String type = 'forward';
    return "forward:/test2?type=" + type;
}

// 重定向
@RequestMapping("/test2")
public String test2(){
    String type = 'redirect';
    return "redirect:/test2?type=" + type;
}Copy to clipboardErrorCopied

在拦截器中,常通过修改 HttpSevletRequest 对象实现请求转发。

request.getRequestDispatcher("login").forward(request,response);Copy to clipboardErrorCopied

Controller 配置

Spring 的 WebMvcConfigurer 接口定义了 Controller 层配置信息(默认为空实现)。

开发者可以通过实现 WebMvcConfigurer 接口或继承 WebMvcConfigurationSupport 类对以下方法进行重写。

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    /** 解决跨域问题 **/
    @Override
    public void addCorsMappings(CorsRegistry registry){};
    /** 添加拦截器 **/
    @Override
    public void addInterceptors(InterceptorRegistry registry){};

}Copy to clipboardErrorCopied

跨域问题

配置如何处理跨域请求,否则返回数据会被浏览器拦截。

@Override
public void addCorsMappings(CorsRegistry registry) {
            // 添加映射路径(全部)
    registry.addMapping("/**")
            // 放行哪些原始域
            .allowedOrigins("*")
            // 是否发送 Cookie 信息
            .allowCredentials(true)
            // 放行哪些原始域(请求方式)
            .allowedMethods("GET","POST", "PUT", "DELETE")
            // 放行哪些原始域(头部信息)
            .allowedHeaders("*")
            // 暴露哪些头部信息
            .exposedHeaders("Header1", "Header2");
}Copy to clipboardErrorCopied

局部跨域

  1. @CrossOrigin 注解:在方法上(@RequestMapping)或者在控制器(@Controller)上使用,可以实现局部跨域。
@RequestMapping("/hello")
@ResponseBody
@CrossOrigin("http://localhost:8080") 
public String index( ){
    return "Hello World";
}Copy to clipboardErrorCopied
  1. 使用 HttpServletResponse 对象添加响应头实现局部跨域。
@RequestMapping("/hello")
@ResponseBody
public String index(HttpServletResponse response){
    response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");         // 指定端口放行
    // response.addHeader("Access-Control-Allow-Origin", "*");                             全部放行
    return "Hello World";
}Copy to clipboardErrorCopied

拦截器 & 过滤器

  • 拦截器(Interceptor)

Java Web 中,在执行 Controller 方法前后对 Controller 请求进行拦截和处理。依赖于 web 框架,在 Spring 配置。在实现上基于 Java 的反射机制。

  • 过滤器(Filter)

Java Web 中,在 request/response 传入 Servlet 前,过滤信息或设置参数。依赖于 servlet 容器,在 web.xml 配置。在实现上基于函数回调。

两者常用于修改字符编码、删除无用参数、登录校验等。Spring 框架中优先使用拦截器:功能接近、使用更加灵活。

拦截器配置

// 在配置中引入拦截器对象(单独编写拦截器类)

@Override
public void addInterceptors(InterceptorRegistry registry) {
    // 导入拦截器对象,默认拦截全部
    InterceptorRegistration addInterceptor = registry.addInterceptor(new myInterceptor());

    // 排除配置
    addInterceptor.excludePathPatterns("/error","/login","/user/login");               
    addInterceptor.excludePathPatterns("/asserts/**");                       
    addInterceptor.excludePathPatterns("/webjars/**");
    addInterceptor.excludePathPatterns("/public/**");
    // 拦截配置
    addInterceptor.addPathPatterns("/**");
}Copy to clipboardErrorCopied

拦截器类通过实现 HandlerInterceptor 接口或者继承 HandlerInterceptorAdapter 类。

// 定义拦截器
public class myInterceptor extends HandlerInterceptorAdapter {

    // Session key
    public final static String SESSION_KEY = "user";

    // preHandle 预处理
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 检查 session
        HttpSession session = request.getSession();
        if (session.getAttribute(SESSION_KEY) != null) return true;
        // 重定向到登录页面
        request.setAttribute("message","登录失败,请先输入用户名和密码。");
        request.getRequestDispatcher("login").forward(request,response);
        return false;
    }

    // postHandle 善后处理
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
        System.out.println("INTERCEPTOR POSTHANDLE CALLED");
    }

}Copy to clipboardErrorCopied

过滤器类通过继承 Filter 类实现,直接添加注解即可。

@Component                                                                // 作为组件,交给容器处理
@ServletComponentScan                                                     // 扫描组件
@WebFilter(urlPatterns = "/login/*",filterName = "loginFilter")           // 设定过滤路径和名称
@Order(1)                                                                 // 设定优先级(值小会优先执行)
public class LoginFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 过滤器前执行
        System.out.println("before");
        // 执行内部逻辑
        filterChain.doFilter(servletRequest,servletResponse);
        // 过滤器后执行
        System.out.println("after");
    }

    @Override
    public void destroy() {
    }
}Copy to clipboardErrorCopied

调用顺序

filter


Spring Boot配置HTTPS

####生成SSL证书

https://www.cnblogs.com/benwu/articles/4891758.html

JDK提供证书管理工具: JDK\bin\keytool.exe

Tomcat使用Java提供的密码库,通过Java的Keytool工具生成JKS等格式的证书文件。 Apache使用OpenSSL提供的密码库,生成PEM、KEY、CRT等格式的证书文件。

cmd命令(JDK\bin目录打开)

密钥库: 保存密钥和对应的证书。【证书只含有公钥】

genkeypair 生成密钥对(非对称加密算法) genseckey 生成密钥(对称加密算法) 创建名为tomcat的密钥对以及自签名的证书,放入mykeystore密钥库中(不存在则创建) keytool -genkeypair -alias "tomcat" -keyalg "RSA" -validity 180 -keypass "123456" -keystore "D:\mykeystore.keystore" -storetype PKCS12 -storepass

  • alias 证书别名
  • keyalg 加密算法,生成密钥对默认RSA
  • keysize 密钥键长,RSA默认2048
  • validity 证书有效期,默认90
  • keypass 证书密码
  • keystore 密钥库路径,默认创建在用户目录下
  • storetype 密钥库类型,默认JKS
  • storepass 密钥库密码

查看密钥库 keytool -list -v -alias tomcat -keystore "D:\mykeystore.keystore" -storepass 123456

将生成的证书文件拷贝到项目resources目录下

####修改全局配置文件

application.properties格式

server.port = 8443
server.ssl.key-store = classpath:mykeystore.keystore
server.ssl.key-store-password = 123456
server.ssl.keyStoreType = PKCS12
server.ssl.keyAlias = tomcatCopy to clipboardErrorCopied

设置SSL后,默认使用HTTPS协议。访问localhost:8443,会出现证书安全提示,强行进入即可。 【未付费注册,不被数字认证机构CA认可:会被浏览器标记为不安全】

如果将服务器端口号设置成443端口,即https的默认访问端口,那么在进行https访问的时候可以不带端口号直接访问。

修改入口文件

如果访问http://localhost:8443,则提示需要TLS。

》》将http连接自动转换为https连接

@Configuration
public class TestSslApplication {
    //servlet容器,自己写的bean会覆盖自动配置的bean?
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createStandardConnector());
        return tomcat;
    }

  // 新建connecter监听80端口,并重定向至8443
    private Connector createStandardConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }

}
Copy to clipboardErrorCopied

重新配置Servlet容器(Tomcat)

自动配置类ServletWebServerFactoryAutoConfiguration会读取bean

https://www.jianshu.com/p/017a7f40efff

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/655597.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

调整表格大小

方法一:使用鼠标拖动表格边框或右下角的调整控点 在Word文档中,选中要缩小的表格,将鼠标指针放在表格的边框线上,直到指针变成双箭头的形状。 按住鼠标左键,拖动边框线,调整表格的宽度或高度。如果同时按住…

01 一文理解,Prometheus详细介绍

01 一文理解,Prometheus详细介绍 介绍 大家好,我是秋意零。 Prometheus 是一个开源的系统监控和报警工具包,最初由SoundCloud开发,并在2012年作为开源项目发布。Prometheus 目前由Cloud Native Computing Foundation&#xff08…

python爬虫之pandas库——数据清洗

安装pandas库 pip install pandas pandas库操作文件 已知在本地桌面有一名为Python开发岗位的csv文件(如果是excel文件可以做简单修改即可,道理是通用的) 打开文件: 打开文件并查看文件内容 from pandas import DataFrame import pandas as pd data_c…

AIGC 010-CLIP第一个文本和图像对齐的大模型!

AIGC 010-CLIP第一个文本和图像对齐的大模型! 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 不客气的说CLIP和扩散模型的成功让计算式视觉领域几乎所有工作都重新做了一遍。 CLIP(对比语言-图像预训练)论文提出了一种新的对比学习方法&a…

【C++课程学习】:二叉树的基本函数实现

🎁个人主页:我们的五年 🔍系列专栏:C课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 🍉二叉树的结构类型: 🍉1.创建二叉树函数(根据数组&am…

如何将云服务器上操作系统由centos切换为ubuntu

本文将介绍如何将我们购买的云服务器上之前装的centos切换为ubuntu,云服务器以华为云为例,要切换的ubuntu版本为ubuntu20.04。 参考官方文档:切换操作系统_弹性云服务器 ECS (huaweicloud.com) 首先打开华为云官网,登录后点击右…

机器学习(五) -- 监督学习(5) -- 线性回归1

系列文章目录及链接 上篇:机器学习(五) -- 监督学习(4) -- 集成学习方法 - 随机森林 下篇:机器学习(五) -- 监督学习(5) -- 线性回归2 前言 tips&#xff1…

树莓派指令

1.常用指令 2.在终端窗口编辑文本文件 2.1nano编辑器 在文本里ctrlG就可以查看更多的快捷按键 2.2vi编辑器 进入默认为命令模式

Spring-Cloud-OpenFeign源码解析-04-调用流程分析

在Spring-Cloud-OpenFeign源码解析-03-FeignClientFactoryBean分析到,通过Autowired或者Resource注入FeignClient实例的时候,实际上返回的是JDK动态代理对象,具体的实现逻辑在InvocationHandler的invoke方法中 回看ReflectiveFeign.newInsta…

怎么简单的把图片缩小?图片在线改大小的方法

在日常工作中经常需要在网上上传图片,但是一般网上不同的平台对上传的图片大小和尺寸都会有限定的要求,不符合要求无法正常上传使用。所以当遇到图片太大的问题时,该如何快速修改图片大小,有很多的小伙伴都很关注这个问题的解决方…

macOS上用Qt creator编译并跑shotcut

1 简介 Shotcut是一个开源的跨平台的视频编辑软件,支持WIN/MACOS/LINUX等平台,由于该项目的编译较为麻烦,踩坑几许,因此写此文章记录完整编译构建过程,后续按此法编译,可减少走弯路,提高生产力。…

Springboot项目打包:将依赖的jar包输出到指定目录

场景 公司要对springboot项目依赖的jar包进行升级,但是遇到一个问题,项目打包之后,没办法看到他里面依赖的jar包,版本到底是不是升上去了,没办法看到。 下面是项目打的jar包 我们通过反编译工具jdgui,来…

Compose Button移除水波纹效果

一、背景 在使用Compose实现Button按钮时,设计要求移除按钮的水波纹效果,只保留按压效果,经查Compose1.4.3版本中,并没有直接移除水波纹的能力 二、遇到问题 经过多次尝试,使用Compose的Button组件始终无法实现目标效…

SpringBoot基础篇

1:parent 目的:减少依赖配置 开发SpringBoot程序要继承spring-boot-starter-parentspring-boot-starter-parent中定义了若干个依赖管理继承parent模块可以避免多个依赖使用相同技术出现依赖版本冲突继承parent的形式也可以采用引入依赖的i形式实现效果…

《java数据结构》--栈的详解

一.栈的认识 栈是一种不同于链表和顺序表的储存数据结构,它对存储数据和取出数据有着特殊的要求🤔。 首先栈只能从一端存储数据,也就是从一端进,还从这一端出这也是栈最大的特点,这也导致在栈中存取数据都必须遵循先…

FreeRtos进阶——队列的特殊用途

信号量与互斥量都一样,都是特殊的队列。但是只有互斥量实现了优先级继承机制。 信号量与互斥量与队列一样,在操作增加或者减少时,必须先关中断在进行操作! 信号量创建揭秘 图中信号量的创建过程,在代码中的体现本质就是…

vue+antd实践:在输入框光标处插入内容

今天来看一个很简单的需求。 需求描述:在输入框光标处,插入指定的内容。 效果如下: 实现思路:刚开始还在想怎么获取光标的位置,但是发现所做的项目是基于vue3antd组件,那么不简单了嘛,只要调…

SwiftUI初探

SwiftUI 虽然出现了好几年(1.0好像2019年出的,还有SPM也是同一年),现在已经到从1.0到5.0,但受限于对系统的要求(最低iOS13.0,有的要求17.0及以上),每个版本里面差异也很大,语法和Flutter 的Dart 比较像。空闲之余可以先…

Design and implementation of robot impedance controller

机器人阻抗控制器的设计与实现是一个复杂但关键的过程,它涉及到多个方面以确保机器人能够在外界环境的影响下保持稳定的性能。以下是对机器人阻抗控制器设计与实现的详细解答: 一、阻抗控制原理 阻抗控制的基本原理是建立一个期望的机器人位置和接触力…

HTML用法介绍

文章目录 一、HTML概念和模版二、常用标签及用法1.p标签2.span标签3.h标签4.hr标签5.img标签6.a标签7.input标签8.table标签 一、HTML概念和模版 HTML的全称为超文本标记语言&#xff0c;它包括一系列标签组成&#xff0c;模版及各部分注释如下&#xff1a; <!--声明文档类…