SpringMVC学习使用
一、SpringMVC简单理解
1.1 Spring与Web环境集成
1.1.1 ApplicationContext应用上下文获取方式
应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件) ,这样的弊端是配置文件加载多次,应用上下文对象创建多次。
在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
1.1.2 Spring提供获取应用上下文的工具
上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。
所以我们需要做的只有两件事:
①在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
②使用WebApplicationContextUtils获得应用上下文对象ApplicationContext
1.1.3 导入Spring集成web的坐标
<!-- spring必要依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.5.RELEASE</version></dependency><!-- spring web依赖注意使用mvc后倒入webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.0.5.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.2</version></dependency><!--Jsp坐标--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version></dependency><!-- Servlet坐标 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency>
1.1.4 配置ContextLoaderListener监听器
<!--全局参数-->
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--Spring的监听器-->
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
1.1.5 通过工具获得应用上下文对象
@WebServlet(name = "TestServlet", value = "/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {ServletContext servletContext = request.getServletContext();WebApplicationContext spring = WebApplicationContextUtils.getWebApplicationContext(servletContext);System.out.println(spring.getBean("user"));}
}
知识要点
Spring集成web环境步骤
①配置ContextLoaderListener监听器
②使用WebApplicationContextUtils获得应用上下文
③spring-web提供的监听器spring-webmvc页提供(同时使用会冲突)
1.2 SpringMVC的简介
1.2.1 SpringMVC概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。
SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
通过属性java类交由spring容器管理,通过注解定义url实现对应的方法执行,简化了servlet定义与书写
1.2.2 SpringMVC简单实现
使用servlet进行控制层处理每一个请求都需要书写一个servlet,每个servlet只修改处理请求的方法与名称,其余没有修改,springMVC可以看做提供了一个中央控制器对这些servlet进行统一的分发管理并简化servlet的书写
①将所有的方法书写在一个java类中 并书写相应地址映射
import java.util.HashMap;//将所有需要执行的方法书写在当前类中
public class AllController {HashMap<String,String> map=new HashMap<>();public void a(){System.out.println("a方法执行");}public void b(){System.out.println("b方法执行");}
}
②书写核心控制器(应该是处理所有请求的servlet)
@WebServlet("/*")
public class AllServlet extends HttpServlet {AllController allController=new AllController();@Overridepublic void init() throws ServletException {HashMap<String, String> map = allController.map;map.put("/day0924/a","a");map.put("/day0924/b","b");}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取实际请求的uriString requestURI = request.getRequestURI();System.out.println("requestURI:"+requestURI);HashMap<String, String> map = allController.map;String methodName = map.get(requestURI);//通过反射调用对应方法Class<AllController> allControllerClass = AllController.class;try {Method declaredMethod = allControllerClass.getDeclaredMethod(methodName);//执行对应方法declaredMethod.invoke(allController);} catch (Exception e) {}}
}
1.2.3 SpringMVC快速入门
需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。
开发步骤
①导入SpringMVC相关坐标
②配置SpringMVC核心控制器DispathcerServlet
③创建Controller类和视图页面
④使用注解配置Controller类中业务方法的映射地址
⑤配置SpringMVC核心文件 spring-mvc.xml
⑥客户端发起请求测试
代码实现
①导入Spring和SpringMVC的坐标、导入Servlet和Jsp的坐标
<!--Spring坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.8.RELEASE</version></dependency><!--SpringMVC坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.8.RELEASE</version></dependency><!--Jsp坐标--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version></dependency><!-- Servlet坐标 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency>
②在web.xml配置SpringMVC的核心控制器与spring加载监听器
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!-- 配置springmvc前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>
</web-app>
③创建Controller和业务方法
public class UserController {public ModelAndView select(ModelAndView mv,HttpServletRequest request){request.setAttribute("msg","查找返回的数据");mv.setViewName("/index.jsp");return mv;}public String update(ModelAndView mv,HttpServletRequest request){request.setAttribute("msg","更新返回的数据");return "/index.jsp";}
}
③创建视图页面index.jsp
<html>
<body><h2>Hello SpringMVC!</h2>${msg}
</body>
</html>
④配置注解
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping("/select.do")public ModelAndView select(ModelAndView mv,HttpServletRequest request){request.setAttribute("msg","查找返回的数据");mv.setViewName("/index.jsp");return mv;}@RequestMapping("/update.do")public String update(ModelAndView mv,HttpServletRequest request){request.setAttribute("msg","更新返回的数据");return "/index.jsp";}
}
⑤创建spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置注解扫描--><context:component-scan base-package="com.yunhe.controller"/>
</beans>
二、SpringMVC常用功能与使用
2.1 SpringMVC的执行流程
①用户发送请求至前端控制器DispatcherServlet。
②DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
④DispatcherServlet调用HandlerAdapter处理器适配器。
⑤HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
⑥Controller执行完成返回ModelAndView。
⑦HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
⑧DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑨ViewReslover解析后返回具体View。
⑩DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
2.1.1 SpringMVC组件解析
-
前端控制器:DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。 -
处理器映射器:HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 -
处理器适配器:HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
-
处理器:Handler
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。 -
视图解析器:View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。 -
视图:View
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
2.1.2 SpringMVC注解解析
@RequestMapping
作用:用于建立请求 URL 和处理请求方法之间的对应关系
位置:
类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录
方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径
属性:
value:用于指定请求的URL。它和path属性的作用是一样的
method:用于指定请求的方式
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
例如:
params = {“accountName”},表示请求参数必须有accountName
params = {“moeny!=100”},表示请求参数中money不能是100
2.1.3 SpringMVC的XML配置解析
- mvc命名空间引入
命名空间:xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"
约束地址:http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
- 组件扫描
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用<context:component-scan base-package=“com.yh.controller"/>进行组件扫描。
SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文件地址org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
翻看该解析器源码,可以看到该解析器的默认设置,如下:
REDIRECT_URL_PREFIX = "redirect:" --重定向前缀
FORWARD_URL_PREFIX = "forward:" --转发前缀(默认值)
prefix = ""; --视图名称前缀
suffix = ""; --视图名称后缀
- 视图解析器
我们可以通过属性注入的方式修改视图的的前后缀
<!--配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"></property><property name="suffix" value=".jsp"></property>
</bean>
2.2 SpringMVC的数据响应
数据响应方式
1) 页面跳转
①直接返回字符串
②通过ModelAndView(HttpServletRequest)对象返回
2) 回写数据
①直接返回字符串
②返回对象或集合
页面跳转-返回字符串形式
第一种形式:
这种方式进行页面跳转一般与HttpServletRequest对象一起使用,在参数列表中声明,将数据存储至作用域中进行传递
第二种形式:
@RequestMapping(value="/quick4")public String save4(Model model){model.addAttribute("username","二狗子");return "success";}
这种方式同样会进行页面跳转,但是数据传递使用model对象,model对象的使用方式与HttpServletRequest类似,可以在jsp中使用el表达式通过key进行获取
页面跳转-通过ModelAndView对象返回
在Controller中方法返回ModelAndView对象,并且设置视图名称
@RequestMapping(value="/quick2")public ModelAndView save2(){/*Model:模型 作用封装数据View:视图 作用展示数据*/ModelAndView modelAndView = new ModelAndView();//设置模型数据modelAndView.addObject("username","二狗子");//设置视图名称modelAndView.setViewName("success");return modelAndView;}
这种方法就是直接将返回的视图与数据一同交由视图解析器进行自动处理
当然也可以不创建ModelAndView对象而是在方法中声明,在Controller中方法形参上直接声明ModelAndView,无需在方法中自己创建,在方法中直接使用该对象设置视图,同样可以跳转页面
@RequestMapping(value="/quick3")public ModelAndView save3(ModelAndView modelAndView){modelAndView.addObject("username","华华");modelAndView.setViewName("success");return modelAndView;}
回写数据-直接返回字符串
通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,此时不需要视图跳转,业务方法返回值为void将需要回写的字符串直接返回,但此时需要通过@ResponseBody注解告知SpringMVC框架通知视图解析器,方法返回的字符串不是跳转是直接在http响应体中返回
@RequestMapping(value="/quick7")@ResponseBody //告知SpringMVC框架 不进行视图跳转 直接进行数据响应public String save7() throws IOException {return "hello yh";}@RequestMapping(value="/quick6")public void save6(HttpServletResponse response) throws IOException {response.getWriter().print("hello yh");}
json字符串也是字符串,所以也可以通过这种方式返回json字符串数据
@RequestMapping(value="/quick8")@ResponseBodypublic String save8() throws IOException {return "{\"username\":\"zhangsan\",\"age\":18}";}
手动拼接json格式字符串的方式很麻烦,开发中往往要将复杂的java对象转换成json格式的字符串,我们可以使用web阶段学习过的json转换工具类进行转换后回写字符串(一般不用手动转换的方式)
回写数据-返回对象或集合
通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></list></property></bean>
@RequestMapping(value="/quick10")@ResponseBody//期望SpringMVC自动将User转换成json格式的字符串public User save10() throws IOException {User user = new User();user.setUsername("张三");user.setAge(18);return user;}
这样配置还是比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置
<mvc:annotation-driven/>
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用<mvc:annotation-driven />
自动加载 RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter( 处 理 适 配 器 ),可用在Spring-xml.xml配置文件中使用<mvc:annotation-driven />
替代注解处理器和适配器的配置。同时使用<mvc:annotation-driven />
默认底层就会集成jackson进行对象或集合的json格式字符串的转换
2.3 SpringMVC的数据请求
客户端请求参数的格式是:name=value&name=value……
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数
①基本类型参数
②类类型参数
③数组类型参数
④集合类型参数
2.3.1 基本类型参数的获取
springmvc会自动进行解析,只需要在controller中的业务方法的参数名称与请求参数的name一致,参数值会自动映射匹配。并且能自动做类型转换;
自动的类型转换是指从String向其他类型的转换(注意类型转换失败的情况)
@RequestMapping(value="/quick11")@ResponseBodypublic void save11(String username,int age){System.out.println(username);System.out.println(age);}
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
当然也可以手动的进行配置获取请求指定的参数,使用RequestParam注解
@RequestParam有以下三个参数:
value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将抛出异常;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值,设置该参数时,自动将required设为false。
public String requestparam(@RequestParam(value="username",required=false) String username)
2.3.2 类类型参数的获取
package com.yunhe.pojo;
public class User {private String username;private int age;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", age=" + age +'}';}
}
@RequestMapping(value="/quick12")@ResponseBodypublic void save12(User user){System.out.println(user);}
2.3.3 数组类型参数的获取
在前台页面提交的数据中,多个数据name相同,springmvc会自动解析成数组,但要求controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。
@RequestMapping(value="/quick13")@ResponseBodypublic void save13(String[] strs) throws IOException {System.out.println(Arrays.asList(strs));}
2.3.4 集合类型参数的获取
springmvc会自动将对个name相同的数据解析为数组,所以在进行集合获取时需要将集合参数包装到一个POJO中才可以。
<form action="${pageContext.request.contextPath}/user/quick14" method="post"><%--表明是第一个User对象的username age--%><input type="text" name="userList[0].username"><br/><input type="text" name="userList[0].age"><br/><input type="text" name="userList[1].username"><br/><input type="text" name="userList[1].age"><br/><input type="submit" value="提交"></form>
package com.yh.domain;import java.util.List;public class VO {private List<User> userList;public List<User> getUserList() {return userList;}public void setUserList(List<User> userList) {this.userList = userList;}@Overridepublic String toString() {return "VO{" +"userList=" + userList +'}';}
}
@RequestMapping(value="/quick14")@ResponseBodypublic void save14(VO vo) throws IOException {System.out.println(vo);}
这种使用方式太过繁琐,对于不同的pojo类需要创建对应的集合类
使用ajax提交json数据获取集合类型参数数据
当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script><script>var userList = new Array();userList.push({username:"zhangsan",age:18});userList.push({username:"lisi",age:28});$.ajax({type:"POST",url:"${pageContext.request.contextPath}/user/quick15",data:JSON.stringify(userList),contentType:"application/json;charset=utf-8"});</script>
@RequestMapping(value="/quick15")@ResponseBodypublic void save15(@RequestBody List<User> userList) throws IOException {System.out.println(userList);}
2.4 SpringMVC静态资源的访问
当有静态资源需要加载时,比如jquery文件,通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,我们可以通过以下两种方式指定放行静态资源:
•在spring-mvc.xml配置文件中指定放行的资源
<mvc:resources mapping="/js/**"location="/js/"/>
•使用<mvc:default-servlet-handler/>
标签
<!--开发资源的访问--><!--<mvc:resources mapping="/js/**" location="/js/"/><mvc:resources mapping="/img/**" location="/img/"/>--><mvc:default-servlet-handler/>
2.5 SpringMVC配置编码过滤器
使用springmvc与servlet一样,当编码不一致时会出现乱码问题,springmvc提供了CharacterEncodingFilter全局过滤器进行全局的编码配置
<!--配置全局过滤的filter--><filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
2.6 SpringMVC配置参数绑定
当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显式的绑定
<form action="${pageContext.request.contextPath}/quick16" method="post"><input type="text" name="name"><br><input type="submit" value="提交"><br>
</form>
@RequestMapping(value="/quick16")@ResponseBodypublic void save16(@RequestParam(value="name",required = false,defaultValue = "yh") String username) throws IOException {System.out.println(username);}
属性:
value :页面数据的name
required :是否必填(如果页面没有传递则报错默认为false)
defaultValue :默认值,当页面没有传递数据时的赋值(默认为数据 类型默认值)
2.7 SpringMVC配置请求类型转换器
SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。
但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。
@component
public class DateConverter implements Converter<String, Date> {public Date convert(String dateStr) {//将日期字符串转换成日期对象 返回SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = format.parse(dateStr);} catch (ParseException e) {e.printStackTrace();}return date;}
}
@RequestMapping(value="/quick18")@ResponseBodypublic void save18(Date date) throws IOException {System.out.println(date);}
<mvc:annotation-driven conversion-service="conversionService"/><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><ref bean="dateConverter"/></set></property></bean>
2.8 请求头信息信息的获取
使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:
value:请求头的名称
required:是否必须携带此请求头
@RequestMapping(value="/quick20")@ResponseBodypublic void save20(@RequestHeader(value = "User-Agent",required = false) String user_agent) throws IOException {System.out.println(user_agent);}
2.9 请求头cookie数据的获取
使用@CookieValue可以获得指定Cookie的值
@CookieValue注解的属性如下:
value:指定cookie的名称
required:是否必须携带此cookie
@RequestMapping(value="/quick21")@ResponseBodypublic void save21(@CookieValue(value = "JSESSIONID") String jsessionId) throws IOException {System.out.println(jsessionId);}
三、SpringMVC使用RESTful风格参数的获取
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
GET:用于获取资源
POST:用于新建资源
PUT:用于更新资源
DELETE:用于删除资源
例如:
/user/1 GET : 得到 id = 1 的 user
/user/1 DELETE: 删除 id = 1 的 user
/user/1 PUT: 更新 id = 1 的 user
/user POST: 新增 user
上述url地址/user/1中的1就是要获得的请求参数,form表单提交数据的方式支持get与post,但是在SpringMVC中可以使用占位符进行参数绑定。地址/user/1可以写成/user/{id},占位符{id}对应的就是1的值。在业务方法中我们可以使用@PathVariable注解进行占位符的匹配获取工作。
http://localhost:8080/springmvc1/quick17/zhangsan
@RequestMapping(value="/quick17/{name}")
@ResponseBodypublic void save17(@PathVariable(value="name") String username) throws IOException {System.out.println(username);}
springmvc使用RESTful风格就是使用占位符的形式,将数据与地址进行绑定,通过@PathVariable注解进行获取,完成通过对不同路径请求完成类似功能的需求
使用axios发送不同的请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><script src="js/axios.min.js"></script>
</head>
<body><button id="btn1">GET请求</button><button id="btn2">POST请求</button><button id="btn3">PUT请求</button><button id="btn4">DELETE请求</button>
</body>
<script>document.getElementById("btn1").onclick=function (){var obj={};axios({// 请求方式method: 'get',url: 'user/1',// 传递参数 data使用流发送数据 params台servlet可以直接获取data: obj,//响应的数据格式 默认就是json 可以省略responseType: 'text'}).then(response => {// 请求成功let res = response.data;console.log(res);}).catch(error => {// 请求失败,console.log(error);// 一般不用});}document.getElementById("btn2").onclick=function (){var obj={id:2,name:"张三"};axios({// 请求方式method: 'post',url: 'user',// 传递参数 data使用流发送数据 params台servlet可以直接获取data: obj,//响应的数据格式 默认就是json 可以省略responseType: 'json'}).then(response => {// 请求成功let res = response.data;console.log(res);}).catch(error => {// 请求失败,console.log(error);// 一般不用});}document.getElementById("btn3").onclick=function (){var obj={id:2,name:"张三2"};axios({// 请求方式method: 'put',url: 'user',// 传递参数 data使用流发送数据 params台servlet可以直接获取data: obj,//响应的数据格式 默认就是json 可以省略responseType: 'json'}).then(response => {// 请求成功let res = response.data;console.log(res);}).catch(error => {// 请求失败,console.log(error);// 一般不用});}document.getElementById("btn4").onclick=function (){var obj={};axios({// 请求方式method: 'delete',url: 'user/4',// 传递参数 data使用流发送数据 params台servlet可以直接获取data: obj,//响应的数据格式 默认就是json 可以省略responseType: 'text'}).then(response => {// 请求成功let res = response.data;console.log(res);}).catch(error => {// 请求失败,console.log(error);// 一般不用});}
</script>
</html>
四、SpringMVC拦截器简单使用
4.1 概念
SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
(1)过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
(2)拦截器:
依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。
1、常见应用场景
1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2)权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。
5)OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。
SpringMVC提供的拦截器接口:HandlerInterceptor
public interface HandlerInterceptor {boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
}
拦截器一个有3个回调方法,而一般的过滤器Filter才两个:
preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器才会执行afterCompletion。
拦截器适配器:HandlerInterceptorAdapter
有时我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,此时spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {}public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {}
}
4.2 简单使用
①自定义两个拦截器(继承拦截器适配器:HandlerInterceptorAdapter):HandlerInterceptor1 和 HandlerInterceptor2
public class HandlerInterceptor1 extends HandlerInterceptorAdapter{@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("--1--HandlerInterceptor1.preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("--1--HandlerInterceptor1.postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("--1--HandlerInterceptor1.afterCompletion");}
}
②在 springmvc.xml 配置文件中配置拦截器:
(1)拦截所有Controller类里的所有处理方法
<!-- 配置拦截器:--><mvc:interceptors><!-- 会拦截所有Controller类里的所有处理方法 --><bean class="com.yunhe.interceptor.HandlerInterceptor1"></bean><bean class="com.yunhe.interceptor.HandlerInterceptor2"></bean></mvc:interceptors>
(2)只拦截某个请求路径的处理方法
<!-- 配置拦截器:--><mvc:interceptors><!-- 会拦截所有Controller类里的所有处理方法 --><bean class="com.yunhe.interceptor.HandlerInterceptor1"></bean><mvc:interceptor><!-- 只拦截该路径 --><mvc:mapping path="/users"/><bean class="com.yunhe.interceptor.HandlerInterceptor2"></bean></mvc:interceptor></mvc:interceptors>
(3)拦截器深入配置:注意 /** (任意分层路径下) ,/* (该任意单路径下) 和 配置順序(先所有后排除)
<!-- 配置拦截器:--><mvc:interceptors><!-- 会拦截所有Controller类里的所有处理方法 --><bean class="com.yunhe.interceptor.HandlerInterceptor1"></bean><mvc:interceptor><!-- 只拦截该路径 --><mvc:mapping path="/users"/><bean class="com.yunhe.interceptor.HandlerInterceptor2"></bean></mvc:interceptor><mvc:interceptor><!-- 拦截所有请求,排除拦截 /toAdd 请求 --><mvc:mapping path="/**"/><mvc:exclude-mapping path="/toAdd"/><bean class="com.yunhe.interceptor.HandlerInterceptor3"></bean></mvc:interceptor></mvc:interceptors>
# 五、SSM整合项目创建
①导入相应的依赖坐标
<!-- spring核心依赖坐标 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.5</version></dependency><!-- springaop织入依赖 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><!-- lombok工具依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.2</version></dependency><!-- spring jdbc依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.5</version></dependency><!-- mysql依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.39</version></dependency><!-- Druid连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- springmvc依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.5</version></dependency><!-- servlet依赖 --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><!-- jsp依赖 --><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version></dependency><!-- jackson依赖 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><!-- mybatis依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!-- mybatis sping整合依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><!--log4j依赖--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
②创建相应的包
③书写mybatis核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 加载properties配置文件 --><!--<properties url=""></properties>--><!-- 为指定的包下的类设置别名(设置pojo 使用首字母小写形式的别名) --><!--<typeAliases><package name=""/></typeAliases>--><!-- 配置mybatis数据源选择操作 --><!--<environments default=""><environment id=""><transactionManager type=""></transactionManager><dataSource type=""></dataSource></environment></environments>--><!-- mybatis的全局配置 基本使用默认 其他可以通过mapper配置文件进行设置 --><settings><setting name="lazyLoadingEnabled" value="true"/><!-- 开启懒加载 --><setting name="aggressiveLazyLoading" value="false"/><!-- 设置懒加载侵入方式 --><setting name="logImpl" value="STDOUT_LOGGING"/><!-- 使用mybatis 自带的日志管理 --></settings><!-- 配置mybatis扫描xml文件所在的包 --><!--<mappers><package name=""/></mappers>--></configuration>
④书写log4j与数据连接配置文件
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
⑤配置spring相关核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- spring组件扫描 --><!-- 将含有对应注解的类交由spring管理 可以实现IOC与DI AOP也必须切入由spring管理的类 --><context:component-scan base-package="com.yunhe"/><!-- 加载properties --><!-- 可以在当前的配置文件中使用${key}的形式获取对应的value值 --><context:property-placeholder location="classpath:db.properties"/><!-- 配置数据源 --><!-- 使用指定的连接池对数据源进行管理 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!-- 配置spring与mybatis整合 --><!-- 配置SqlSessionFactoryBean对象,整合加载mybatis配置文件 使用mybatis进行数据源操作 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 将数据源交由mybatis进行管理 --><property name="dataSource" ref="dataSource"/><!-- 配置mybatis配置文件 --><!-- 加载mybatis核心配置文件(进行修改时) --><property name="configLocation" value="classpath:mybatis.xml"/><!-- 配置mapper映射文件 --><!-- 在创建mybatis时加载所有的mapper.xml --><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!-- mybatis.spring自动映射,DAO接口所在包名,Spring会自动查找其下的类 --><!-- 根据加载的mapper.xml创建相应的实现类 并交由spring容器管理 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.yunhe.mapper" /></bean><!--平台事务管理器--><!-- 创建相应的事务代理对象交由spring容器管理 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 开启事务的注解驱动 --><!-- 将拥有事务处理的方法进行事务代理 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 设置aop织入自动代理 --><!-- 才会将相应的切面类织入指定的切入点(方法) --><aop:aspectj-autoproxy/><!-- springmvc视图解析器 --><!-- 在controller返回的视图名进行拼接返回对应视图 --><!-- 如果需要使用其他的视图模板或插件也是在视图解析器进行配置 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/view/"></property><property name="suffix" value=".jsp"></property></bean><!-- 开启springmvc注解驱动 --><mvc:annotation-driven/><!-- 开启静态资源默认过滤 --><mvc:default-servlet-handler/><!-- 指定静态资源过滤 --><!--<mvc:resources mapping="" location=""></mvc:resources>--></beans>
⑥配置web.xml
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!-- springmvc编码控制器 --><filter><filter-name>Encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class></filter><filter-mapping><filter-name>Encoding</filter-name><url-pattern>*</url-pattern></filter-mapping><!-- springmvc前端控制器 --><servlet><servlet-name>mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>mvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
⑦书写相应的代码测试ssm整合是否成功
User.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int uid;private String uusername;private String upassword;
}
UserMapper.java
public interface UserMapper {ArrayList<User> selectAll();
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yunhe.mapper.UserMapper"><select id="selectAll" resultType="com.yunhe.pojo.User">select * from user</select></mapper>
UserService.java
public interface UserService {public ArrayList<User> findAll();
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic ArrayList<User> findAll() {return userMapper.selectAll();}
}
UserController.java
@Controller
public class UserController {@Autowiredprivate UserService userServiceImpl;@RequestMapping("/all")public String find(HttpServletRequest request){request.setAttribute("msg",userServiceImpl.findAll());return "success";}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>
UserController.java
@Controller
public class UserController {@Autowiredprivate UserService userServiceImpl;@RequestMapping("/all")public String find(HttpServletRequest request){request.setAttribute("msg",userServiceImpl.findAll());return "success";}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>
<select id="selectAll" resultType="com.yunhe.pojo.User">select * from user
</select>
```
UserService.java
public interface UserService {public ArrayList<User> findAll();
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic ArrayList<User> findAll() {return userMapper.selectAll();}
}
UserController.java
@Controller
public class UserController {@Autowiredprivate UserService userServiceImpl;@RequestMapping("/all")public String find(HttpServletRequest request){request.setAttribute("msg",userServiceImpl.findAll());return "success";}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>
UserController.java
@Controller
public class UserController {@Autowiredprivate UserService userServiceImpl;@RequestMapping("/all")public String find(HttpServletRequest request){request.setAttribute("msg",userServiceImpl.findAll());return "success";}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>
相关文章:
SpringMVC学习使用
一、SpringMVC简单理解 1.1 Spring与Web环境集成 1.1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(sp…...
MySQL | MySQL安装教程
MySQL | MySQL安装教程(压缩包(ZIP)安装-详细版) 🪄个人博客:https://vite.xingji.fun MySQL概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,MySQL AB公司被Sun公司收购,Sun公…...
Vite入门指南
一、什么是Vite? Vite(法语意为"快速")是由Vue作者尤雨溪开发的新型前端构建工具。它基于原生ES模块(ESM)实现,具有以下核心优势: 极速启动:冷启动时间比Webpack快10-10…...
DeepSeek 助力 Vue 开发:打造丝滑的进度条
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
左移架构 -- 从攒批,湖仓到使用数据流的实时数据产品
编辑导读: 这篇文章翻译自 Kai Waehner的 《The Shift Left Architecture – From Batch and Lakehouse to Real-Time Data Products with Data Streaming》。文章通过数据产品的概念引出了如何创建可重复使用的数据产品使企业能够从当前和未来的数据中获得价值。基于构建数据产…...
用java实现word(docx)转换为pdf格式文档(简单版)
导入依赖 <dependency> <groupId>com.documents4j</groupId> <artifactId>documents4j-local</artifactId> <version>1.0.3</version> </dependency> <dependency>…...
【云安全】云原生- K8S etcd 未授权访问
什么是etcd? etcd 是一个开源的分布式键值存储系统,主要用于存储和管理配置信息、状态数据以及服务发现信息。它采用 Raft 共识算法,确保数据的一致性和高可用性,能够在多个节点上运行,保证在部分节点故障时仍能继续提…...
【Elasticsearch】字符过滤器Character Filters
在 Elasticsearch 中,字符过滤器(Character Filters)是文本分析器的重要组成部分,用于在分词之前对原始文本进行预处理。它们可以对字符流进行转换,例如添加、删除或更改字符。Elasticsearch 提供了三种内置的字符过滤…...
网络工程师 (35)以太网通道
一、概念与原理 以太网通道,也称为以太端口捆绑、端口聚集或以太链路聚集,是一种将多个物理以太网端口组合成一个逻辑通道的技术。这一技术使得多个端口能够并行工作,共同承担数据传输任务,从而提高了网络的传输能力和可靠性。 二…...
浏览器网络请求全流程深度解析
一、核心流程概述 现代浏览器的网络请求过程是一个分层协作的精密系统,涉及应用层协议、传输层协议、操作系统内核及网络基础设施的协同工作。整个过程可抽象为以下关键阶段: 请求构建与初始化DNS解析与寻址TCP连接建立HTTP协议交互响应处理与资源解析…...
arduino扩展:Arduino Mega 控制 32 个舵机(参考表情机器人)
参考:表情机器人中使用22个舵机的案例 引言 在电子制作与自动化控制领域,Arduino 凭借其易用性和强大的扩展性备受青睐。Arduino Mega 作为其中功能较为强大的一款开发板,具备丰富的引脚资源,能够实现复杂的控制任务。舵机作为常…...
时间盲注,Boolean盲注
什么是SQL注入(SQL Injection) SQL注入是指攻击者通过构造恶意SQL语句来操控数据库,通常发生在Web应用程序未对用户输入进行充分验证的情况下。 什么是盲注(Blind SQL Injection) 盲注就是通过使用巧妙的SQL语句&am…...
小程序canvas2d实现横版全屏和竖版逐字的签名组件(字帖式米字格签名组件)
文章标题 01 功能说明02 效果预览2.1 横版2.2 竖版 03 使用方式04 横向签名组件源码4.1 html 代码4.2 业务 Js4.3 样式 Css 05 竖向签名组件源码5.1 布局 Html5.2 业务 Js5.3 样式 Css 01 功能说明 技术栈:uniapp、vue、canvas 2d 需求: 实现横版的全…...
wireshark网络抓包
由于图片和格式解析问题,可前往 阅读原文 到这里已经讲了两个抓包工具的使用了,大家应该对抓包不是很陌生了。而wireshark相对于fiddler和charles更加偏向于网络层面的抓包或者说是一个网络封包分析工具。使用对象更适合于网络相关人员(网络管理员/相关运…...
jenkins备份还原配置文件
下载ThinBackup插件 方式1 从插件市场直接下载 Manage Jenkins->Manage Plugins->可选插件搜索 注意:有时可能因为网络或者版本问题下载不了,好像是默认下载最新版本,可选择手动安装! 方式二 手动安装插件 点击查看手…...
C# 两种方案实现调用 DeepSeek API
目录 序 开发运行环境 访问API的一个通用方法 原生官网实现 申请 API key 调用实现 调用示例 腾讯云知识引擎原子调用 申请 API key 调用示例 小结 序 DeepSeek(深度求索) 最近可谓火爆的一塌糊涂,具体的介绍这里不再赘述&#x…...
Kimi杨植麟该为“重投放”反思吗?
Kimi原本验证的市场规律被撕裂了。 作者|文昌龙 编辑|杨舟 “没有人提杨植麟了,Kimi花了这么多钱买用户也买不过豆包,到头来都敌不过界面简陋、功能单一的DeepSeek。还是应该把精力和资源集中在做出更好的基础模型才是王道。” 这番话,来自…...
25农村发展研究生复试面试问题汇总 农村发展专业知识问题很全! 农村发展复试全流程攻略 农村发展考研复试真题汇总
农村发展复试当然有好的建议!前提是复试重点面试题背好! 你是不是也在为农村发展考研复试发愁?担心自己准备不充分、表现不好?别急!今天,学姐——复试面试拿下90分成功上岸的学姐,来给大家分享…...
JavaScript函数与方法详解
目录 一、函数的定义 1. 函数声明 2. 函数表达式 3. 箭头函数 二、函数的调用 1. 调用方式 2. 参数数量的灵活性 三、arguments 对象 1. 基本概念 2. 属性 3. 应用场景 4. 转换为真数组 5. 总结 四、Rest参数 1. 基本概念 2. 特点 3. 应用场景 4. 总结 五、变…...
AI 网关对决:Higress 与 OneAPI 的功能对比
什么是 AI 网关? AI 网关旨在统一管理与各种大型语言模型(LLMs)的交互。通过提供单一入口点,它解决了使用来自不同供应商的多个 AI 模型所带来的复杂性问题。这不仅简化了访问流程,提高了系统稳定性,还降低…...
封装一个sqlite3动态库
作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、项目案例 二…...
1.攻防世界 unserialize3(wakeup()魔术方法、反序列化工作原理)
进入题目页面如下 直接开审 <?php // 定义一个名为 xctf 的类 class xctf {// 声明一个公共属性 $flag,初始值为字符串 111public $flag 111;// 定义一个魔术方法 __wakeup()// 当对象被反序列化时,__wakeup() 方法会自动调用public function __wa…...
DeepSeek能做分析吗?从需求规约到分析类图的实验
DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 今天我们来尝试DeepSeek能不能帮我们从需求转到分析。 给定一个用例规约,我们让它按照面向对象分析设计方法,出一个分析类图。过程如下: 可以帮助提…...
九.Spring Boot使用 ShardingSphere + MyBatis + Druid 进行分库分表
文章目录 前言一、引入依赖二、创建一个light-db_1备用数据库三、配置文件 application-dev.yml四、创建shardingsphere-config.yml完整项目结构 五、测试总结 前言 在现代化微服务架构中,随着数据量的不断增长,单一数据库已难以满足高可用性、扩展性和…...
RNN复兴!性能反超Transformer,训练速度提升1300倍!
在最新的顶会论文中,RNN的改进创新更是层出不穷。Bengio团队提出的minLSTM和minGRU,通过去除隐藏状态的依赖和简化门控机制,显著减少了参数量和计算量。这些模型可以使用并行扫描算法进行训练,大大加快了训练速度。例如࿰…...
C语言第18节:自定义类型——联合和枚举
1. 联合体 C语言中的联合体(Union)是一种数据结构,它允许在同一内存位置存储不同类型的数据。不同于结构体(struct),结构体的成员各自占有独立的内存空间,而联合体的所有成员共享同一块内存区域…...
2025年二级建造师报名流程图解
2025年二级建造师报名时间!附报名流程! ⏰️已公布25年二建考试时间的省份如下: ️4月19日、20日考试的城市有:贵州 ️5月10日、11日考试的城市有:湖北、陕西、宁夏、甘肃、福建、浙江、江西、黑龙江、河南、湖南、…...
AWTK fscript 中的 TCP/UDP 客户端扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 TCP/UDP 客户端扩展函数。 1.iostream_tcp_create 创建 TCP 客户端输入输出流对象。 原型 iostream_tcp_create(host, por…...
用php tp6对接钉钉审批流的 table 表格 明细控件 旧版sdk
核心代码 foreach ($flows[product_list] as $k>$gift) {$items_list[] [[name > 商品名称, value > $gift[product_name] ?? ],[name > 规格, value > $gift[product_name] ?? ],[name > 数量, value > $gift[quantity] ?? ],[name > 单位, v…...
【DuodooBMS】给PDF附件加“受控”水印的完整Python实现
给PDF附件加“受控”水印的完整Python实现 功能需求 在实际工作中,许多文件需要添加水印以标识其状态,例如“受控”“机密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是…...
前缀和算法篇:解决子数组累加和问题
前缀和算法篇:解决子数组累加和问题 1.前缀和原理 那么在介绍前缀和的原理之前,那么我们先来说下前缀和最基本的一个应用场景,那么就是如我们标题所说的子数组累加和问题,那么假设我们现在有一个区间为[L,R]的数组,那…...
大语言模型多代理协作(MACNET)
大语言模型多代理协作(MACNET) Scaling Large-Language-Model-based Multi-Agent Collaboration 提出多智能体协作网络(MACNET),以探究多智能体协作中增加智能体数量是否存在类似神经缩放定律的规律。研究发现了小世界协作现象和协作缩放定律,为LLM系统资源预测和优化…...
vue项目使用vite和vue-router实现history路由模式空白页以及404问题
开发项目的时候,我们一般都会使用路由,但是使用hash路由还是history路由成为了两种选择,因为hash路由在url中带有#号,history没有带#号,看起来更加自然美观。但是hash速度更快而且更通用,history需要配置很…...
【Linux】从一台windows电脑访问局域网下另一台linux电脑详细操作步骤
以下是在Windows电脑B上访问Linux电脑A的文件并使用bash终端的详细步骤: 一、在Linux电脑A上配置SSH服务(用于终端操作) 安装SSH服务 sudo apt update && sudo apt install openssh-server启动SSH服务并设置开机自启 sudo systemctl …...
Makefile的用法及算法应用
编译的过程 算法:解决特定问题的求解步骤 算法的设计 1.正确性 语法正确合法的输入能得到合理的结果对非法的输入,给出满足要求的规格说明对精心选择,甚至刁难的测试都能正常运行,结果正确 2.可读性,便于交流&…...
Elasticsearch:15 年来致力于索引一切,找到重要内容
作者:来自 Elastic Shay Banon 及 Philipp Krenn Elasticsearch 刚刚 15 岁了!回顾过去 15 年的索引和搜索,并展望未来 15 年的相关内容。 Elasticsearch 刚刚成立 15 周年。一切始于 2010 年 2 月的一篇公告博客文章(带有标志性的…...
MongoDB 扩缩容实战:涵盖节点配置、服务启动与移除操作
#作者:任少近 文章目录 一、扩容在245节点上配置配置config server:配置mongos启动config server安装工具mongosh添加245新节点到副本集配置分片副本集启动路由并分片 二、缩容Conf server上去掉server4shard上去掉server4mongos上去掉server4 一、扩容…...
Bitmap在数仓中的应用
一、背景 在数据仓库的日常工作中,我们经常需要面对海量数据的存储和高效查询问题。尤其是,当业务对性能的要求越来越高、数据量持续增长时,传统的处理方式往往显得笨拙而低效。而这时候,Bitmap(位图)作为…...
C++病毒(^_^|)(2)
第二期 声明: 仅供损害电脑,不得用于非法。损坏电脑,作者一律不负责。此作为作者原创,转载请经过同意。 直接上代码 #include <bits/stdc.h> #include <windows.h> using namespace std; HHOOK g_hHook;void lrud(…...
Linux 内核架构入门:从基础概念到面试指南*
1. 引言 Linux 内核是现代操作系统的核心,负责管理硬件资源、提供系统调用、处理进程调度等功能。对于初学者来说,理解 Linux 内核的架构是深入操作系统开发的第一步。本篇博文将详细介绍 Linux 内核的架构体系,结合硬件、子系统及软件支持的…...
leetcode-495.提莫攻击
leetcode-495.提莫攻击 文章目录 leetcode-495.提莫攻击一.题目描述二.代码提交三.解释 一.题目描述 二.代码提交 #include <vector> using namespace std;int findPoisonedDuration(vector<int>& timeSeries, int duration) {int total 0;for (int i 0; i …...
mysql 参数max_connect_errors研究
1.在server端设置max_connect_errors3,超过3次连接错误就block mysql> set global max_connect_errors3; Query OK, 0 rows affected (0.00 sec) mysql> show variables like max_connect_errors; --------------------------- | Variable_name | Value…...
vscode无法ssh连接远程机器解决方案
远程服务器配置问题 原因:远程服务器的 SSH 服务配置可能禁止了 TCP 端口转发功能,或者 VS Code Server 在远程服务器上崩溃。 解决办法 检查 SSH 服务配置:登录到远程服务器,打开 /etc/ssh/sshd_config 文件,确保以下…...
sql盲注获取数据库的表名、列名和具体数据
1.时间盲注 获取表名 sql id1 AND IF(ASCII(SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schemaDATABASE() LIMIT 1),1,1))97, SLEEP(5), 0) 获取列名 sql id1 AND IF(ASCII(SUBSTRING((SELECT column_name FROM information_schema.col…...
清华大学新闻与传播学院沈阳团队出品的《DeepSeek:从入门到精通》104页PDF
前言 本机运行DeepSeek R1大模型文章如下: Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)【保姆级万字教程】在Windows计算机部署DeepSeek大模型,给在实验室无外网的同事们用(基于Ollama和OpenWebUI…...
使用sublime_text中,TAB键无效怎么解决???
如果你也有这样的困扰,请你跟着我下面的步骤操作 点击首选项(如下图所示) 找到下面这段代码并注释掉 { “keys”:[“tab”], “args”:{“action”:“expand_abbreviation”}, “command”:“run_emmet_action”, “context”:[ { “key”:“…...
Java IO流详解
1. IO概述 IO(Input/Output)即输入和输出,指的是设备或环境之间进行数据的输入或输出。例如,键盘是输入设备,显示器是输出设备。在Java中,输入输出问题通过流(Stream)对象来解决。以…...
智慧农业-虫害及生长预测
有害生物防控系统是一个综合性的管理体系,旨在预防和控制对人类生活、生产甚至生存产生危害的生物。这些生物可能包括昆虫、动物、植物、微生物乃至病毒等。 一、系统构成 1、监测预警系统:利用智能传感器、无人机、遥感技术等手段,实时监测…...
ASIL D要达到多少fit
ASIL(Automotive Safety Integrity Level,汽车安全完整性等级)D是ISO 26262标准中最高等级的安全要求,其对应的随机硬件故障概率目标(以FIT表示)需满足以下要求: ASIL D的FIT目标 根据 ISO 262…...
与传统光伏相比 城电科技的光伏太阳花有什么优势?
相比于传统光伏,城电科技的光伏太阳花有以下优势: 一、发电效率方面 智能追踪技术:光伏太阳花通过内置的智能追踪系统,采用全球定位跟踪算法,能够实时调整花瓣(即光伏板)的角度,确…...