Spring MVC(三)- 处理器与注解

news2024/12/23 8:50:56

 Spring MVC 用@Controller及@RestController 注解来标志(自动扫描并注册成bean)该类是一个控制器容器类,在该类下,使用@RequestMapping及其扩展注解来定义处理器。使用注解,可以定义请求的映射、请求的输入、异常处理等。

1 映射请求

使用@RequestMapping 注解来将不同的请求映射到对应的处理器方法上,可以通过URL、请求方法、请求参数、请求头及媒体类型来作匹配。基于其的扩展注解是针对了具体的请求方法做匹配:@GetMapping、@PostMapping等。

1.1 URI 模式

可以使用通配符来匹配请求的URL。

模式

描述

例子

?

匹配一个任意字符。

“/user/get?”

匹配:“/user/get1”

不匹配:“/user/get12”

*

匹配0个或多个任意字符。

“/user/*/get”

匹配:“/user/g1/get”

不匹配:“/user/g1/g2/get”

**

匹配0或多个路径段,直到路径段结束。

“/user/*/get”

匹配:“/user/get”、

“/user/g1/g2/get”

{name}

匹配一个路径段,并捕获它赋值到变量“name”。

“/user/{id}/info”

匹配:“/user/1234/info”,变量id 值为1234。

不匹配:“/user/12/34/info”

{name:[a-z]+}

匹配一个符合表达式段路径段、并捕获它赋值到变量“name”。

“/user/{id:\\d+}/info”,

匹配:“/user/1234/info”

不匹配:“/user/12a/info”

表 @RequestMapping 支持的匹配模式

上面捕获并赋值到变量,可以在处理器方法参数中,通过@PathVariable注解来获取。

@GetMapping("/user/{id:\\d+}/info")
public Pet findPet(@PathVariable Long id) {
    // 请求 /user/123/info,则该方法参数id的值为123
}

1.1.1 RFD(反射型文件下载)漏洞

是一个针对客户端的攻击漏洞,主要发生在响应中设置了“Content-Disposition”头,并且该头的filename属性是由用户请求输入的。这是因为Spring 并没有对用户请求传入的文件名进行严格检测。为了防止该漏洞,开发者应该:

  1. 对filename 参数进行严格的验证和过滤,确保它只包含合法的字符,并且不会造成混淆。
  2. 使用白名单验证,只允许预定义的、安全的文件名格式。
  3. 避免将用户提供的输入直接用作文件名。
@Controller 
public class FileDownloadController { 

    // 假设我们有一个文件路径 
    private static final String FILE_PATH = "path/to/your/file.txt"; 

    @GetMapping("/download") 
    public void downloadFile(@RequestParam String filename, HttpServletResponse response) throws IOException { 

        // 这里故意没有验证和过滤filename参数,导致RFD漏洞 
        Path filePath = Paths.get(FILE_PATH); 
        String contentType = Files.probeContentType(filePath); 
        response.setContentType(contentType); 

        // 使用用户提供的filename作为Content-Disposition中的文件名 
        String headerValue = String.format("attachment; filename=\"%s\"", filename); 
        response.setHeader("Content-Disposition", headerValue); 
        // 将文件内容写入响应输出流 
        Files.copy(filePath, response.getOutputStream()); 
        response.flushBuffer(); 
    } 
}
上面代码中,假如用户的请求是:http://localhost:8080/download?filename=malicious.txt%0D%0AContent-Type:%20text/html%0D%0A%0A<script>alert('Your computer has been compromised!')</script>
那么将可能导致客户端浏览器接收到一个格式不正确的响应,并且可能会执行注入的脚本。

1.2 窄化请求

@RequestMapping 注解还可以通过Media Types、请求参数及请求头等方式来窄化请求匹配。

1.2.1 Media Types

其属性consumes表示请求头的Content-Type,而produces表示响应的Content-Type,由请求头的Accept属性决定。

@PostMapping(path = "/pets", consumes = "application/json",produces = "application/json")
public Object addPet(@RequestBody Pet pet) {
    // 表示该请求头的Content-Type 包含 application/json,Accept包含application/json
}

1.2.2 请求参数与请求头

其属性params 用来表示匹配的请求参数值,而headers 则表示匹配的请求头属性值。

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue", headers = "Content-Type =application/json ")
public void findPet(@PathVariable String petId) {
  // .请求参数中,参数名为myParam的值要为myValue,请求头的Content-Type属性为//application/json(如果是这个请求头属性,则最好用consumes属性来指定)
}

1.3 其他请求方法

HEAD

与GET请求类似,但是响应只返回HTTP头信息,不返回实际的响应体。请求会被服务器处理。用于请求资源的元数据,常用于检查资源是否存在、更新状态或其他头部信息。

OPTIONS

用于获取目标资源所支持的请求方法。常用于跨域请求,在发送可能被视为有风险的请求(如POST或PUT)之前,浏览器可能会先发出一个OPTIONS请求来检查服务器是否允许这种请求。

表 HEAD 与 OPTION 请求

1.4 动态注册处理器

可以通过动态编程方式来动态地注册映射器。

@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, DynamicHandler handler) throws NoSuchMethodException {
    RequestMappingInfo mappingInfo = RequestMappingInfo.paths("/dynamic").methods(RequestMethod.GET).build();
    Method method = DynamicHandler.class.getMethod("showInfo"); // 处理方法
    mapping.registerMapping(mappingInfo,handler,method);
}

2 处理器方法

@RequestMapping 注解方法时,可以为这个方法定义灵活的签名。选择一些列受支持的参数类型和返回值类型。

常见的方法类型参数有:

  1. HttpServletRequest 和 HttpServletResponse 对象。
  2. @PathVariable、@RequestParam、@RequestHeader等注解标注的参数,用于从请求中提取信息。
  3. @ModelAttribute注解标记的参数,用于绑定请求参数到模型对象。
  4. java.util.Map或org.springframework.ui.Model对象,用于添加模型属性等。

常见的返回值类型有:

  1. 字符串(通常表示逻辑视图名)。
  2. ModelAndView对象(包含视图和模型数据)。
  3. ResponseEntity对象(用于构建HTTP响应)。
  4. @ResponseBody 注解标记的对象(Spring MVC会将其序列化为JSON或XML并返回给客户端)。
  5. void(通常与HttpServletResponse对象一起使用以之间写入响应体)。

2.1 参数变量

2.1.1 矩阵变量

URL中,允许在路径段中使用键值对参数。变量用;分割。例如:

/usr;name=黄先生;gender=男/city;address=深圳

注意: 默认情况下,Spring MVC并不支持从URL中解析矩阵变量。要启用对矩阵变量的支持,需要自定义RquestMappingHanddlerMapping的PathMatcher,或者重写WebMvcConfigurer接口的configurePathMatch方法,并设置一个自定义UrIPathHelper,调用其方法setRemoveSemicolonContent(false),来告诉Spring不要移除URL中的分号。

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    UrlPathHelper urlPathHelper = new UrlPathHelper();
    urlPathHelper.setRemoveSemicolonContent(false);// 不要移除URL中的分号
    configurer.setUrlPathHelper(urlPathHelper);
}

可以通过@MatrixVariable 来提取这些变量,用MultiValueMap来装载所有的变量。

// /parameter/matrix1/admin;color=blue;name=jack
@GetMapping("/matrix1/{usr}") // 注意,这里一定要使用路径变量,路径变量后的矩阵变量才会生效
// 所以 /parameter/matrix1;color=red,yellow;size=big/admin;color=blue;name=jack 将匹配失败
public void matrix1(@PathVariable String usr,@MatrixVariable MultiValueMap<String,Object> map) {
    System.out.println("user:" + usr); // user:admin
    System.out.println("map:" + map); //map:{color=[blue], name=[jack]}
}

// parameter/matrix2/admin;subject=English,computer;age=19/sz;subject=math
@GetMapping("/matrix2/{usr}/{address}")
public void matrix2(@PathVariable String usr,@PathVariable String address,@MatrixVariable MultiValueMap<String,Object> map) {
    System.out.println("user:" + usr + ";address:" + address); // user:admin;address:sz
    System.out.println("map:" + map); // map:{subject=[English, computer, math], age=[19]}
}

// parameter/matrix3/admin;subject=English,computer;age=19/sz;subject=math
@GetMapping("/matrix3/{usr}/{address}")
public void matrix3(@PathVariable String usr,@PathVariable String address,@MatrixVariable(name = "subject", pathVar = "usr") List<String> subject1
,@MatrixVariable(name = "subject", pathVar = "address") String subject2) {
    System.out.println("subject1:" + subject1); // subject1:[English, computer]
    System.out.println("subject2:" + subject2); // subject2:math
}

2.1.2 会话变量

会话允许开发者在多个请求之间保持用户的状态信息。

HTTP协议本身是无状态的,服务器不会记住每个用户的请求之间的任何信息。然而,在实际开发者,我们经常需要跟踪用户的会话状态,如登录状态。

在Spring MVC中,会话通常由HttpServletSession对象来管理,这是Java Servlet API的一部分。其提供了存储和检索属性的方法,这些属性可以在用户的整个会话期间保持。

当用户第一次访问一个需要会话支持的Web应用时,Servlet容器在会话被创建时自动生成JESSIONID。如果要保持同一会话,则每次请求时,在cookie中需要携带这个会话ID。

@SessionAttributes

作用于类级别,将模型Model中的属性同步到HTTP会话中。默认请求下,模型中的数据存储到request域。该注解可以指定哪些模型属性存储到session中,使得这些属性可以在其他请求中共享。

@SessionAttribute

从会话中提取属性值

表Spring MVC中的会话属性注解

@RequestMapping("/session")
@RestController
@SessionAttributes("user")
public class SessionController {
    @GetMapping("/login")
    public void login(@RequestParam("username") String username, HttpServletRequest request, Model model) {
        System.out.println("login:" + request.getSession().getId());
        model.addAttribute("user",username);
        model.addAttribute("info","登录了");
    }

    @GetMapping("/info")
    public String info(@SessionAttribute("user") String user,HttpServletRequest request) { // 如果该sessionAttribute的值不存在,则请求会失败
        System.out.println("info:" + request.getSession().getId()); // 会话id需与上面的请求保持一致,才能获取到特定会话的值
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + ":" + cookie.getValue());
        }
        return user;
    }
}

2.1.3 @ModelAttribute

可以作用于有返回值的方法及处理器的参数,用于将属性值绑定到model的属性中,以用于在视图中使用。

作用于方法级别时,会在每次请求处理之前被调用,并且返回的模型属性会被添加到模型中,供后续的请求处理方法使用。

作用于处理器参数时,先从上面的方法返回值来填充模型,然后如果请求参数中包含了相应属性,则会用请求参数值进行覆盖。

@RequestMapping("/modelAttribute")
@RestController
public class ModelAttributeController {
    @ModelAttribute // 该方法会在每次请求处理之前被调用
    public User createUser() {
        return new User("刘女士","123456");
    }

    // /modelAttribute?username=黄先生
    @GetMapping
    public void get2(@ModelAttribute("user") User user) { // 如果传参的时候没有username及password属性,
        // 那么user的值为createUser的返回值,否则request的参数会覆盖其属性值
        System.out.println(user); // ModelAttributeController.User(username=黄先生, password=123456)
    }

    @Data
    public static class User {
        public String username;
        public String password;
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    }
}

2.1.4 @RequestParam 与 @RequestPart

@RequestPart 主要用于处理multipart/form-data类型的请求。注意,@RequestParam 同样也可以读取该类型的参数。区别在于,@RequestPart能读取参数类型为json的参数,并将其转化为对于的类型,而@RequestParam只能把它当作String类型处理。

@RequestMapping("/paramAndPart")
@RestController
public class ParamAndPartController {
    @PostMapping("/param")
    public void param(@RequestParam("jsonValue") String jsonValue,@RequestParam("file") MultipartFile file) throws IOException {
        System.out.println("jsonValue:" + jsonValue);
        System.out.println("file:" + file); // 获取的是文件路径或者文件名等文本信息,而不是文件本身的内容
        System.out.println(file.getInputStream()); // 到这里才涉及文件的操作,获取文件本身的内容
    }

    @PostMapping("/part")
    public void part(@RequestPart("jsonValue") User jsonValue, @RequestPart("file") MultipartFile file) throws IOException {
        System.out.println("jsonValue:" + jsonValue);
        System.out.println("file:" + file); // 会接收客户端发送的数据文件,并将其存储在服务端的临时文件中
        System.out.println(file.getInputStream());
    }

    @Data
    public static class User implements Serializable {
        String username;
        String password;
    }
}

图 使用postman时需要注意的地方

2.1.5 @RequestBody 与 HttpEntity

@RequestBody 的主要作用是自动将HTTP请求的请求体(body)中的数据绑定到方法参数上。这些数据通常以JSON或XML格式发送。使用该注解时,必须确保请求头中的Content-Type属性值正确地制定了请求体的格式。例如,对于JSON数据,Content-Type通常设置为application/json。@RequestBody 只能绑定一个请求体。

HttpEntity 用于表示一个HTTP请求和响应的实体。实例类有RequestEntity、ResponseEntity。如果将其用于参数的绑定请求体的格式要求与@RequestBody一样。

@RestController
@RequestMapping("/myRequestBody")
public class RequestBodyController {
    @PostMapping
    public void requestBody(@RequestBody User user) {
        System.out.println(user);
    }

    @PostMapping("/httpEntity")
    public void httpEntity(HttpEntity<User> userHttpEntity) {
        System.out.println(userHttpEntity.getBody());
    }

    @Data
    public static class User implements Serializable {
        private String username;
        private String password;
    }
}

2.2 响应

2.2.1 Flash Attributes

当我们进行重定向时,需要向后面的处理器传递参数,可以通过URL参数形式传递,但这样不安全。这时我们可以使用Flash Attributes。

其提供了一种在重定向期间保持状态信息的有效方式,同时避免了将状态信息存储在用户会话中的长期副作用。它一旦被读取,就会自动从session中删除。

@Controller
@RequestMapping("/flash")
public class FlashAttributeController {
    @GetMapping("/login")
    public String login(@RequestParam String username, RedirectAttributes redirectAttributes) {
        System.out.println("login username:" + username);
        redirectAttributes.addFlashAttribute("username",username);
        return "redirect:info";
    }

    @GetMapping("/info")
    public @ResponseBody String showInfo(@ModelAttribute("username") String username) {
        System.out.println("hello " + username);
        return username;
    }
}

2.2.2 @ReponseBody 与 ResponseEntity

@ResponseBody 主要用于将控制器方法返回的对象转换为特定的格式,并直接写入HTTP响应的body中。

ResponseEntity 表示整个HTTP响应,包括状态代码、响应体。其优先级高于@ResponseBody,即返回类型为ResponseEntity的情况下,即使方法同时标注了@ResponseBody,也不会对响应体产生影响。

2.2.3 JSON Views

Spring MVC 为Jackson的序列化视图提供了内置支持。序列化视图允许你在一个对象中选择性的包含某些字段,而不是所有字段。要与@ResponseBody或ResponseEntity一起使用。

@RestController
@RequestMapping("/jsonView")
public class JsonViewController {

    @GetMapping
    @JsonView(User.ShowAttribute.class)
    public User showUser() {
        User user = new User("黄先生", 28, "深圳");
        System.out.println(user); // JsonViewController.User(name=黄先生, age=28, address=深圳)
        return user; // 返回给前端 {"name": "黄先生", "address": "深圳"}
    }

    @Data
    public static class User {
        public interface ShowAttribute {}

        @JsonView(ShowAttribute.class)
        public String name;
        private Integer age;
        @JsonView(ShowAttribute.class)
        private String address;
        public User(String name, Integer age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    }
}

3 Controller的配置

3.1 @InitBinder

可以在控制器中指定多个@InitBinder方法,这些方法会在请求处理之前被调用,用于配置数据绑定。通过这些方法,可以定制WebDataBinder的行为。其作用范围为当前Controller下的所有请求(有数值绑定的)。

其具体作用是:1)自定义数据绑定;2)全局配置;3)处理特定类型的参数;4)处理空值或缺失值。

@RestController
@RequestMapping("/initBinder")
public class InitBinderController {
    @InitBinder
    public void initBinder1(WebDataBinder webDataBinder) {
        System.out.println("initBinder1");
    }

    @InitBinder
    public void initBinder2(WebDataBinder webDataBinder) {
        webDataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    @GetMapping
    public void req1(@RequestParam String username) {
        System.out.println("req1:" + username);
    }
}

3.2 @ControllerAdvice

允许开发者定义全局的异常处理、数据绑定等逻辑,而不必在每个单独的controller中重复相同的代码。类似于AOP中的切面,但它专为web层设计。

@ControllerAdvice
public class CustomControllerAdvice {
    @InitBinder
    public void initBinder(WebDataBinder binder) { // 在请求中,方法参数中每有一个参数执行绑定,则该方法都会执行
        System.out.println("CustomControllerAdvice 全局数据绑定处理"); // 可用来配置转换器
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> exceptionHandler(Exception e) { // 全局异常处理
        return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ModelAttribute("webName")
    public String webName() {
        System.out.println("全局@ModelAttribute");
        return "Hello Web";
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot的mysql实现读写分离

前言: 首先思考一个问题:在高并发的场景中,关于数据库都有哪些优化的手段&#xff1f;常用的有以下的实现方法:读写分离、加缓存、主从架构集群、分库分表等&#xff0c;在互联网应用中,大部分都是读多写少的场景,设置两个库,主库和读库,主库的职能是负责写,从库主要是负责读…

鸿蒙一次开发,多端部署(十一)交互归一

对于不同类型的智能设备&#xff0c;用户可能有不同的交互方式&#xff0c;如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配&#xff0c;会增加开发工作量同时产生大量重复代码。为解决这一问题&#xff0c;我们统一了各种交互方式的API&#xff0c;即实现了交…

Qt如何直接处理系统事件(比如鼠标事件),而不是post事件

#include <QtGui/5.15.2/QtGui/qpa/qwindowsysteminterface.h> // 方便调试事件 QWindowSystemInterface::setSynchronousWindowSystemEvents(true); 直接再 qWindowsWndProc函数中处理 通常情况: 事件被放到一个队列中

【vue3.0】实现导出的PDF文件内容是红头文件格式

效果图: 编写文件里面的主要内容 <main><div id"report-box"><p>线索描述</p><p class"label"><span>线索发现时间:</span> <span>{{ detailInfoVal?.problem.createdDate }}</span></p><…

springboot295基于Mysql的商业辅助决策系统的设计与实现

商业辅助决策系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统收支信息和销售订单信息管…

C#,图论与图算法,有向图(Direct Graph)广度优先遍历(BFS,Breadth First Search)算法与源程序

1 图的广度优先遍历 图的广度优先遍历(或搜索)类似于树的广度优先遍历(参见本文的方法2)。这里唯一需要注意的是,与树不同,图可能包含循环,因此我们可能再次来到同一个节点。为了避免多次处理节点,我们使用布尔访问数组。为简单起见,假设所有顶点都可以从起始顶点到达…

python的stone音乐播放器的设计与实现flask-django-php-nodejs

该系统利用python语言、MySQL数据库&#xff0c;flask框架&#xff0c;结合目前流行的 B/S架构&#xff0c;将stone音乐播放器的各个方面都集中到数据库中&#xff0c;以便于用户的需要。该系统在确保系统稳定的前提下&#xff0c;能够实现多功能模块的设计和应用。该系统由管理…

python的OA公文发文管理系统flask-django-php-nodejs

采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”的思想&#xff0c;在OA公文发文管理系统实现了用户、公文分类、公文信息、待办提醒等的功能性。系统根据现有的管理模块进行开发和扩展&a…

hyperf 二十八 修改器 一

教程&#xff1a;Hyperf 一 修改器和访问器 根据教程&#xff0c;可设置相关函数,如set属性名Attribute()、get属性名Attribute()&#xff0c;设置和获取属性。这在thinkphp中也常见。 修改器&#xff1a;set属性名Attribute()&#xff1b;访问器&#xff1a;get属性名Attri…

StarRocks-2.5.13部署安装

1、安装jdk11 tar xf jdk-11.0.16.1_linux-x64_bin.tar.gz mv jdk-11.0.16.1 /data/soft/jdk-11 # 配置在/etc/profile中 export JAVA_HOME/data/soft/jdk-11 export CLASSPATH.:/data/soft/jdk-11/lib export PATH/data/soft/jdk-11/bin:$PATH # 验证jdk [rootdb-public-03 s…

基于ArcGIS的2015-2020辽宁省土地利用变化分析

数据准备 栅格转面 运行ArcToolbox&#xff0c;打开【转换工具】&#xff0c;选择【从栅格转出】里面的【栅格转面工具】&#xff0c;调出面板进行参数设置。输入栅格选择裁剪的2015年中国土地利用遥感监测数据&#xff08;…

Jupyter R绘图 汉字显示乱码的解决办法

1.Jupyte中&#xff0c;R绘图&#xff0c;汉字显示乱码 2.如何解决&#xff1f; (1)R中安装showtext 登录linux服务器 #R > install.packages(“showtext”) … 出错 (2)退出R,安装freetype-config #apt install libfreetype6-dev 出错 &#xff08;3&#xff09;进入R&…

嵌入式Linux 内核启动过程详解(第一阶段:汇编语言部分)

目录 概述 1 简述PC Linux 启动过程 2 嵌入式Linux内核启动流程 2.1 嵌入式Linux内核启动分析 2.2 启动Linux内核前的准备 2.3 启动内核第一阶段流程图 3 嵌入式Linux内核启动分析 3.1 链接文件 vmlinux.lds 3.2 启动文件head.S 3.2 启动文件head-common.S 概述 本文…

2024蓝桥杯每日一题(哈希)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;星空之夜 试题二&#xff1a;模拟散列表 试题三&#xff1a;字符串哈希 试题四&#xff1a;四数方和 试题五&#xff1a;扫雷 试题一&#xff1a;星空之夜 【题目描述】 夜空深…

【JavaScript 漫游】【041】File 对象、FileList 对象、FileReader 对象

文章简介 本篇文章为【JavaScript 漫游】专栏的第 041 篇文章&#xff0c;主要对浏览器模型中 File 对象、FileList 对象和 FileReader 对象的知识点进行了简记。 File 对象 File 对象代表一个文件&#xff0c;用来读写文件信息。它继承了 Blob 对象&#xff0c;或者说是一种…

Springboot+vue的四川美食分享网站+数据库+报告+免费远程调试

项目介绍: Springbootvue的四川美食分享网站。Javaee项目&#xff0c;springboot vue前后端分离项目 本文设计了一个基于Springbootvue的前后端分离的四川美食分享网站&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&am…

计算机视觉之三维重建(3)---单视几何

文章目录 一、问题提出二、无穷远点、无穷远线、无穷远平面2.1 2D空间2.2 3D空间 三、影消点和影消线3.1 2D平面上的无穷远点&#xff0c;无穷远线变换3.2 影消点3.3 影消线 四、单视重构 一、问题提出 1. 当摄像机标定后&#xff0c;内部参数 K K K 已知&#xff0c;外部参数…

界面控件DevExpress ASP.NET Ribbon组件 - 完美复刻Office 365体验!

无论用户是喜欢传统工具栏菜单外观、样式&#xff0c;还是想在下一个项目中复制Office 365 web UI&#xff0c;DevExpress ASP.NET都提供了所需要的工具&#xff0c;帮助用户打造更好的应用程序界面。 P.S&#xff1a;DevExpress ASP.NET Web Forms Controls拥有针对Web表单&a…

JavaWeb -- HTTP -- WEB服务器TOMCAT

一.HTTP介绍: HTTP(Hyper Text Protocol) 实际上是一种超文本传输的协议,规定了浏览器跟服务器之间的一些数据传输的规则 例如B/S 对于浏览器的请求,以及相应服务器的响应,都必须依靠这种协议,规范,才能够彼此之间相互 理解 HTTP的协议特点: 1.基于TCP协议: 面向连接 更加安全…

Vscode初建Vue时几个需要注意的问题

首先放图 注意点1.打开文件夹时&#xff0c;可以是VUE2 或者其他&#xff0c;但不能是VUE&#xff0c;会报错 注意点2.终端输入命令“npm init -y" npm init -y -y 的含义&#xff1a;yes的意思&#xff0c;在init的时候省去了敲回车的步骤&#xff0c;生成的默认的packag…