当前位置: 首页 > news >正文

太原网站优化教程/百度网站首页提交入口

太原网站优化教程,百度网站首页提交入口,企业网站制作模板免费,龙岗做网站哪里找文章目录写在前面处理器映射上下文参数无注解下获取参数使用注解RequestParam获取参数数组参数JSON参数URL包含参数数据转换器参数转换流程Converter实践自定义转换器domain类控制器接口浏览器验证postman验证HttpMessageConverter说明数据验证Hibernate Validator验证添加依赖…

文章目录

  • 写在前面
  • 处理器映射
  • 上下文参数
    • 无注解下获取参数
    • 使用注解@RequestParam获取参数
    • 数组参数
    • JSON参数
    • URL包含参数
  • 数据转换器
    • 参数转换流程
    • Converter实践
      • 自定义转换器
      • domain类
      • 控制器接口
      • 浏览器验证
      • postman验证
    • HttpMessageConverter说明
  • 数据验证
    • Hibernate Validator验证
      • 添加依赖
      • 验证实体
      • 引入注解@Valid
      • 模拟访问
    • 自定义验证
      • 验证机制
      • 验证实体
      • 自定义验证器
      • 控制器方法
      • 模拟访问
  • 数据模型
  • 视图和视图解析器
    • thymeleaf配置
    • jsp配置
  • 文件上传
    • StandardServletMultipartResolver
    • yml
    • 控制器方法示例
    • 接口设计
  • 拦截器
    • XSS过滤
      • 配置文件
      • XssFilterConfig
      • XssFilter
      • XssHttpServletRequestWrapper
      • EscapeUtil
      • HTMLFilter
    • 防重复提交
  • 国际化
  • 结尾

在《初识 Spring MVC,知道这些就够了》中,我从应用的角度粗略总结了一下Spring MVC的知识,这一篇章我将从更为细致的角度去总结一下相关知识。我打算从处理器映射、上下文参数、数据转换器、数据验证、数据模型、视图和视图解析器、文件上传、拦截器、国际化等方面分别进行总结,并总结一些实际应用案例。

写在前面

强大的Spring已经做到了框架的天花板,作为一个java工程师必须深入了解Spring,我带着学习的心态,将Spring MVC又重新深入了解一下,希望带来更深层次的思索,授业解惑。

处理器映射

在上一章的介绍中,我们已经知道一个请求从客户端过来,会找到请求对应的控制器,那么这一过程是怎么实现的,我接下来就要分析一下这个过程。
我把springboot工程中logging.level.org.springframework日志级别改为trace,这样我们可以看到系统启动时,RequestMappingHandlerMapping组件会检测到所有@Controller控制器的@RequestMapping方法,日志如下图:

14:29:42.373 [restartedMain] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - [detectHandlerMethods,292] - c.r.w.c.d.c.DemoDialogController:{GET [/demo/modal/parent]}: parent(){GET [/demo/modal/layer]}: layer(){GET [/demo/modal/check]}: check(){GET [/demo/modal/table]}: table(){GET [/demo/modal/form]}: form(){GET [/demo/modal/radio]}: radio(){GET [/demo/modal/frame2]}: frame2(){GET [/demo/modal/dialog]}: dialog(){GET [/demo/modal/frame1]}: frame1()

当一个请求"/captcha/captchaImage"发送到服务器的时候,DispatcherServlet会先根据请求找到"sysCaptchaController"组件,然后找到该组件的"getKaptchaImage"方法进行处理。
在这里插入图片描述这些都归功于@RequestMapping、@PostMapping、@GetMapping、@PutMapping、@DeleteMapping等注解,我以GetMapping为例看下源码:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = {RequestMethod.GET}
)
// 仅限于get请求了
public @interface GetMapping {@AliasFor(annotation = RequestMapping.class)// 配置请求映射名称String name() default "";@AliasFor(annotation = RequestMapping.class)String[] value() default {};@AliasFor(annotation = RequestMapping.class)// 通过路径映射String[] path() default {};@AliasFor(annotation = RequestMapping.class)// 限定参数String[] params() default {};@AliasFor(annotation = RequestMapping.class)// 限定请求头String[] headers() default {};@AliasFor(annotation = RequestMapping.class)// 限定提交类型,即本方法消费什么类型的数据,如application/jsonString[] consumes() default {};@AliasFor(annotation = RequestMapping.class)// 限定响应内容类型,即指定生产什么类型的数据String[] produces() default {};
}

上下文参数

在实际应用过程中,获取参数有多种方式,最常见的有如下几种:

  • 无注解下获取参数
  • 使用注解@RequestParam获取参数
  • 数组参数
  • JSON参数
  • URL包含参数

无注解下获取参数

控制器方法

@Controller
@RequestMapping("/test")
public class TestController {@RequestMapping("/hello")@ResponseBodypublic String hello(String username) {return "hello, " + username;}
}

浏览器请求

http://127.0.0.1:8080/test/hello?username=lilei
在这里插入图片描述

postman请求
在这里插入图片描述

由此可以看出,只需要控制器接口参数名称和http请求参数名称保持一致。

使用注解@RequestParam获取参数

控制器方法

    @RequestMapping("/hi")@ResponseBodypublic String hi(@RequestParam("user_name") String username) {return "hi, " + username;}

浏览器请求

http://127.0.0.1:8080/test/hi?user_name=lilei

在这里插入图片描述
postman请求

在这里插入图片描述

@RequestParam注解实现了控制器参数和http请求参数的映射关系,且默认情况下参数不能为空,可以使用required=false属性进行设置。

数组参数

控制器方法

    @RequestMapping("/welcome")@ResponseBodypublic String welcome(String[] usernames) {for (String username : usernames) {System.out.println(username);}return "welcome";}

浏览器请求

http://127.0.0.1:8080/test/welcome?usernames=lilei,lili,ligang
在这里插入图片描述

postman请求
在这里插入图片描述后台输出

在这里插入图片描述

JSON参数

@Data
public class User {private Long id;private String name;private Integer age;private String email;private String city;
}
    @RequestMapping("/user")@ResponseBodypublic String user(@RequestBody User user) {System.out.println(user.toString());return user.toString();}

postman请求
在这里插入图片描述

@RequestBody注解表示控制器方法接收前端提交的JSON数据格式的请求体,JSON请求体参数名称和User属性名称保持一致。

URL包含参数

控制器方法

    @RequestMapping("/viewuser/{id}")@ResponseBodypublic String viewuser(@PathVariable("id") String id) {System.out.println(id);return id;}

浏览器请求

http://127.0.0.1:8080/test/viewuser/1

在这里插入图片描述

数据转换器

在上下文参数章节,我们得知控制器接收参数时进行了自动转换,这是因为spring内置了很多数据转换器,比如最长用的:StringHttpMessageConverter、MappingJackson2HttpMessageConverter。

参数转换流程

在这里插入图片描述

  • Converter,普通转换器接口
  • Formatter,格式化转换器
  • GenericConverter,可以将参数转换为数组

在SpringMVC中,这三类接口实现可通过注册机接口注册,注册后控制器就可以获取对应的转换器来实现参数的转换。

在Spring Boot中,使用WebMvcAutoConfiguration中内部类WebMvcAutoConfigurationAdapter的addFormatters方法来注册。

    // WebMvcAutoConfigurationAdapterpublic void addFormatters(FormatterRegistry registry) {ApplicationConversionService.addBeans(registry, this.beanFactory);}// ApplicationConversionServicepublic static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {Set<Object> beans = new LinkedHashSet();beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());beans.addAll(beanFactory.getBeansOfType(Converter.class).values());beans.addAll(beanFactory.getBeansOfType(Printer.class).values());beans.addAll(beanFactory.getBeansOfType(Parser.class).values());Iterator var3 = beans.iterator();while(var3.hasNext()) {Object bean = var3.next();if (bean instanceof GenericConverter) {registry.addConverter((GenericConverter)bean);} else if (bean instanceof Converter) {registry.addConverter((Converter)bean);} else if (bean instanceof Formatter) {registry.addFormatter((Formatter)bean);} else if (bean instanceof Printer) {registry.addPrinter((Printer)bean);} else if (bean instanceof Parser) {registry.addParser((Parser)bean);}}}

在Spring Boot的工程中,只需要定义一个Converter组件即可。

知道了转换器的原理以及注册机制后,那么我们实践一下如何自定义一个数据转换器呢,比如我们传送一个分数参数,我们需要将分数按照A、B、C、D、E分等级(grade)。

Converter实践

只需要定义一个@Component组件即可。

自定义转换器

@Component
public class StringToGradeConverter implements Converter<String, Grade> {@Overridepublic Grade convert(String source) {// http字符串参数Long s = Long.parseLong(source);if (s < 60) {return new Grade(s, "E");} else if (s < 70) {return new Grade(s, "D");} else if (s < 80) {return new Grade(s, "C");} else if (s < 90) {return new Grade(s, "B");} else if (s < 100) {return new Grade(s, "A");} else {return new Grade(s, "A+");}}
}

domain类

public class Grade {public Grade(Long score, String grade) {this.fs = score;this.dj = grade;}private Long fs;private String dj;public Long getFs() {return fs;}public void setFs(Long fs) {this.fs = fs;}public String getDj() {return dj;}public void setDj(String dj) {this.dj = dj;}@Overridepublic String toString() {return "Grade{" +"fs=" + fs +", dj='" + dj + '\'' +'}';}
}

控制器接口

@RestController
@RequestMapping("/test")
public class GradeController {public static final Logger logger = LoggerFactory.getLogger(GradeController.class);@RequestMapping("/converter")public String converter(Grade grade){logger.info(grade.toString());return grade.toString();}}

浏览器验证

http://127.0.0.1:8080/test/converter?grade=88

返回结果:
在这里插入图片描述

postman验证

在这里插入图片描述

HttpMessageConverter说明

HttpMessageConverter接口负责将http请求体转换成对应的java对象。
比如@RequestBody注解,通过HttpMessageConverter来实现请求体和java对象之间的解析。

数据验证

参数转换后,处理器还可以进行参数验证,以保障后边进行的业务逻辑处理。

Hibernate Validator验证

添加依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

验证实体

public class User {private Long id;@NotNull(message = "名称不能为空")private String name;private Integer age;private String email;private String city;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", email='" + email + '\'' +", city='" + city + '\'' +'}';}
}

引入注解@Valid

    @RequestMapping("/user")@ResponseBodypublic String user(@Valid @RequestBody User user) {System.out.println(user.toString());return user.toString();}

模拟访问

在这里插入图片描述

后台报org.springframework.web.bind.MethodArgumentNotValidException异常

自定义验证

验证机制

在这里插入图片描述

Validator验证器接口,实现这个接口定义自己的验证器。
@InitBinder注解用来绑定验证器,在控制器方法调用前会调用。

验证实体

package com.example.entity;public class User {private Long id;private String name;private Integer age;private String email;private String city;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", email='" + email + '\'' +", city='" + city + '\'' +'}';}
}

自定义验证器

package com.example.config;import com.example.entity.User;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;public class UserValidator implements Validator {// 需要验证的实体类型,true验证,false否@Overridepublic boolean supports(Class<?> clazz) {return clazz.equals(User.class);}/*** 验证规则* @param target 验证对象* @param errors 错误对象*/@Overridepublic void validate(Object target, Errors errors) {// 验证年龄必须大于18User user = (User) target;if (user.getAge() != null && user.getAge() < 18) {errors.rejectValue("age", null, "未成年");return;}}}

控制器方法

package com.example.web;import com.example.config.UserValidator;
import com.example.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.validation.Valid;@Controller
public class UserController {/*** 绑定自定义验证器* 其它方法调用前,先执行该绑定方法* @param binder*/@InitBinderpublic void initBinder(WebDataBinder binder) {binder.setValidator(new UserValidator());}/*** 验证器实践接口* @param user* @return*/@RequestMapping("/user/validator")@ResponseBodypublic String user(@Valid @RequestBody User user) {System.out.println(user.toString());return user.toString();}
}

如何在控制器方法获取到验证的错误信息,需要使用org.springframework.validation.Errors

    // 可以通过Errors获取验证信息@RequestMapping("/user/validator")@ResponseBodypublic String user(@Valid @RequestBody User user, Errors errors) {System.out.println(user.toString());for (ObjectError error : errors.getAllErrors()) {System.out.println(error.getDefaultMessage());}return user.toString();}

模拟访问

在这里插入图片描述后台日志:

Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.web.UserController.user(com.example.entity.User): [Field error in object 'user' on field 'age': rejected value [14]; codes [user.age,age,java.lang.Integer,]; arguments []; default message [未成年]] ]

数据模型

数据模型的作用是绑定数据,为后面的视图渲染做准备。

在这里插入图片描述
我在实际项目中常用ModelMap,如下方法所示:

    @GetMapping("/edit/{deptId}")public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap){mmap.put("dept", deptService.selectDeptById(deptId));return prefix + "/edit";}

视图和视图解析器

视图的作用是渲染数据模型展示给用户,分为逻辑视图(如InternalResourceViewResolver)和非逻辑视图(如MappingJackson2JsonView)。
默认的视图解析器配置:org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
逻辑视图中我们经常使用的是jthymeleaf和jsp。

thymeleaf配置

spring:# 模板引擎thymeleaf:mode: HTMLencoding: utf-8# 禁用缓存cache: false

默认配置:

package org.springframework.boot.autoconfigure.thymeleaf;import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.MediaType;
import org.springframework.util.MimeType;
import org.springframework.util.unit.DataSize;@ConfigurationProperties(prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING;public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";private boolean checkTemplate = true;private boolean checkTemplateLocation = true;private String prefix = "classpath:/templates/";private String suffix = ".html";private String mode = "HTML";......   
}

jsp配置

spring:# jsp configmvc:view:prefix: /WEB-INF/viewssuffix: .jsp

文件上传

在spring-boot-autoconfigure包内的org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration类中,已经默认配置了StandardServletMultipartResolver,所以我们只需要简单的配置一下yml参数即可。

StandardServletMultipartResolver

@Configuration(proxyBeanMethods = false
)
@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})
@ConditionalOnProperty(prefix = "spring.servlet.multipart",name = {"enabled"},matchIfMissing = true
)
@ConditionalOnWebApplication(type = Type.SERVLET
)
@EnableConfigurationProperties({MultipartProperties.class})
public class MultipartAutoConfiguration {private final MultipartProperties multipartProperties;public MultipartAutoConfiguration(MultipartProperties multipartProperties) {this.multipartProperties = multipartProperties;}@Bean@ConditionalOnMissingBean({MultipartConfigElement.class, CommonsMultipartResolver.class})public MultipartConfigElement multipartConfigElement() {return this.multipartProperties.createMultipartConfig();}@Bean(name = {"multipartResolver"})@ConditionalOnMissingBean({MultipartResolver.class})public StandardServletMultipartResolver multipartResolver() {StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());return multipartResolver;}
}

yml

spring:servlet:# 上传下载配置multipart:# 单个文件大小max-file-size: 1MB# 设置总上传的文件大小max-request-size: 10MB

控制器方法示例

    @PostMapping("/common/upload")@ResponseBodypublic HashMap<String, String> uploadFile(MultipartFile file) throws Exception{HashMap ajax = new HashMap<String, String>();try{// 上传文件路径,windows和linux有区别,本示例在windows环境String filePath = "D:/uploadPath";// 设定文件名称,实际中需要是动态扩展的,比如添加目录层级String fileName = file.getOriginalFilename();File desc = new File(filePath + File.separator + fileName);// 关键是这句代码,拷贝文件file.transferTo(desc);// pathFileName和url实际中也需要动态处理String pathFileName = "需要返回的路径";String url = "http://127.0.0.1:8080/" + pathFileName;ajax.put("code", 0);ajax.put("fileName", pathFileName);ajax.put("url", url);}catch (Exception e){ajax.put("code", 500);}return ajax;}

接口设计

在这里插入图片描述

拦截器

实际项目中常用的拦截器有防跨站攻击(Xss)、防重复提交。

XSS过滤

配置文件

xss:# 过滤开关enabled: true# 非过滤链接(多个用逗号分隔)excludes: /platform/notice/*# 过滤链接urlPatterns: /user/*,/role/*,/dept/*

XssFilterConfig

@Configuration
public class XssFilterConfig
{@Value("${xss.enabled}")private String enabled;@Value("${xss.excludes}")private String excludes;@Value("${xss.urlPatterns}")private String urlPatterns;@SuppressWarnings({ "rawtypes", "unchecked" })@Beanpublic FilterRegistrationBean xssFilterRegistration(){// 注册过滤器到servlet 3.0+容器FilterRegistrationBean registration = new FilterRegistrationBean();// 设置dispatcher类型,此处为request,registration.setDispatcherTypes(DispatcherType.REQUEST);// 设置过滤器对象registration.setFilter(new XssFilter());// 过滤请求路径registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));registration.setName("xssFilter");registration.setOrder(Integer.MAX_VALUE);Map<String, String> initParameters = new HashMap<String, String>();initParameters.put("excludes", excludes);initParameters.put("enabled", enabled);// 设置过滤器初始化参数registration.setInitParameters(initParameters);return registration;}
}

XssFilter

public class XssFilter implements Filter {/*** 排除链接*/public List<String> excludes = new ArrayList<>();/*** xss过滤开关*/public boolean enabled = false;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 获取排除链接String tempExcludes = filterConfig.getInitParameter("excludes");String tempEnabled = filterConfig.getInitParameter("enabled");if (StringUtils.isNotEmpty(tempExcludes)) {String[] url = tempExcludes.split(",");for (int i = 0; url != null && i < url.length; i++) {excludes.add(url[i]);}}if (StringUtils.isNotEmpty(tempEnabled)) {enabled = Boolean.valueOf(tempEnabled);}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;// 处理需要排除过滤的链接if (handleExcludeURL(req, resp)) {chain.doFilter(request, response);return;}// 包装请求对象XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);chain.doFilter(xssRequest, response);}/** 处理需要排除过滤的链接*   开关关闭,所有链接都不过滤*   excludes 参数为空,默认全部过滤*   在excludes 参数中找到具体链接,则进行过滤*   默认全部过滤*/private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {// 开关关闭返回trueif (!enabled) {return true;}// 排除链接为空返回falseif (excludes == null || excludes.isEmpty()) {return false;}String url = request.getServletPath();for (String pattern : excludes) {Pattern p = Pattern.compile("^" + pattern);Matcher m = p.matcher(url);if (m.find()) {return true;}}// 默认返回falsereturn false;}@Overridepublic void destroy() {}
}

XssHttpServletRequestWrapper

/**包装请求对象*  处理参数特殊字符*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {/*** @param request*/public XssHttpServletRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);if (values != null) {int length = values.length;String[] escapseValues = new String[length];for (int i = 0; i < length; i++) {// 防xss攻击和过滤前后空格escapseValues[i] = EscapeUtil.clean(values[i]).trim();}return escapseValues;}return super.getParameterValues(name);}
}

EscapeUtil

若依框架工具类:EscapeUtil

HTMLFilter

若依框架工具类:HTMLFilter

防重复提交

主要思路是对相同请求的参数是否一致,以及两次请求(参数一致)的时间差进行对比(小于10秒,可变)。使用缓存或者session以请求url为key,进行存储参数和时间戳,每次请求会更新当前缓存信息。

若依框架拦截器:SameUrlDataInterceptor

国际化

请移阅“面向全球的用户,我们该怎么办”

结尾

自此SpringMVC的主要知识点就梳理完成了,我知道了这些,再也不怕别人问我SpringMVC相关知识了。

http://www.lbrq.cn/news/1439767.html

相关文章:

  • 企业网站建设 建立作用/做网站企业
  • 合肥专业网站建设/简述如何对网站进行推广
  • 石家庄上门足疗/网站seo优化方案
  • 深圳网络seo优化/网站需要怎么优化比较好
  • 品牌网站建设仁術大蝌蚪/百度seo官方网站
  • 观澜网站建设/网站seo优化运营
  • 什么网站可以做实验室/精准ip地址查询工具
  • 抖音小程序推广怎么挂才有收益/哈尔滨关键词优化报价
  • 柳州网站建设33/大地seo视频
  • 辽宁城乡建设工程招标网(官网)/网站seo关键词优化技巧
  • 企业网站开发需要多钱/百度ocpc如何优化
  • 免费的ppt网站推荐/如何建立网页
  • 计算机专业网站建设实训日志/网站seo入门基础教程
  • 销售网站免费做/哈尔滨电话本黄页
  • 建站之星极速版/晨阳seo顾问
  • 如何开网站建设公司/沈阳网络优化培训
  • 河北手机网站制作公司/武汉网站排名提升
  • 公司网站建设好处/盘多多搜索引擎入口
  • 珠海网站建设制作怎么收费/免费python在线网站
  • 搭建h5流程/江苏搜索引擎优化公司
  • 计算机的网站建设/查询网站信息
  • 怎么用java做html5网站/百度首页排名代发
  • 上海商务网站建设/百度广告费
  • 网上有哪些购物网站/查网站
  • 做买东西的网站要多少钱/专业网站建设公司
  • 公司网站建设7个基本流程/淘宝搜索词排名查询
  • 网站开发需要哪些人员/如何在百度搜索到自己的网站
  • 莘县网站建设公司/百度推广登录首页网址
  • 为把网站建设更好/短视频营销成功案例
  • 徐州铜山区建设局网站/淘宝关键词指数
  • 【P21】OpenCV Python——RGB和BGR,HSV和HSL颜色空间,及VScode中报错问题解决
  • BGE:智源研究院的通用嵌入模型家族——从文本到多模态的语义检索革命
  • 西门子S7-200与S7-1200通过PPI以太网模块通讯,赋能汽车制造行业发展
  • PO、BO、VO、DTO、POJO、DAO、DO基本概念
  • lesson35:数据库深度解析:从概念到MySQL实战学习指南
  • GPT-5 全面解析与最佳实践指南