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

成都住房和城乡建设部网站1v1网站建设

成都住房和城乡建设部网站,1v1网站建设,厦门做百度推广的网站,科技设计网站建设Java进击框架#xff1a;Spring-Web#xff08;八#xff09; 前言DispatcherServlet拦截器异常视图解析重定向转发 语言环境日志 过滤器带注释的控制器声明映射请求其它注解验证 功能性端点URI Links异步请求CORSHTTP缓存视图技术MVC配置其他Web框架 前言 Spring Web MVC是… Java进击框架Spring-Web八 前言DispatcherServlet拦截器异常视图解析重定向转发 语言环境日志 过滤器带注释的控制器声明映射请求其它注解验证 功能性端点URI Links异步请求CORSHTTP缓存视图技术MVC配置其他Web框架 前言 Spring Web MVC是构建在Servlet API上的原始Web框架从一开始就包含在Spring框架中。正式名称“Spring Web MVC”来自其源模块的名称(spring-webmvc)但更通俗的说法是“springMVC”。Spring Framework 5.0引入了一个反应式堆栈Web框架它的名字“Spring WebFlux”也是基于它的源模块(spring-webflux)。 DispatcherServlet 与许多其他web框架一样Spring MVC是围绕前端控制器模式设计的其中中心Servlet DispatcherServlet为请求处理提供共享算法而实际工作由可配置的委托组件执行。这个模型是灵活的并且支持不同的工作流。 DispatcherServlet和任何Servlet一样需要通过使用Java配置或在web.xml中根据Servlet规范声明和映射。 Java配置示例示例代码如下 Configuration //启用 Spring MVC EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {// 配置静态资源处理Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(/static/**).addResourceLocations(/static/);}// 配置视图解析器Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver new InternalResourceViewResolver();resolver.setPrefix(/WEB-INF/views/);//前缀resolver.setSuffix(.jsp);//后缀return resolver;} } public class MyWebApplicationInitializer implements WebApplicationInitializer {Overridepublic void onStartup(ServletContext servletContext) throws ServletException {// 创建 AnnotationConfigWebApplicationContext 并注册配置类AnnotationConfigWebApplicationContext ctx new AnnotationConfigWebApplicationContext();ctx.register(MyWebMvcConfig.class);// 创建 DispatcherServlet 并注册到 ServletContextDispatcherServlet dispatcherServlet new DispatcherServlet(ctx);//向 ServletContext 中注册了一个名为 app 的 ServletServletRegistration.Dynamic registration servletContext.addServlet(app, dispatcherServlet);//表示在容器启动时就立即初始化并加载这个 Servletregistration.setLoadOnStartup(1);//将这个Servlet映射到根路径(/)。//这意味着当用户访问应用的根路径时例如 http://localhost:8080/容器会将请求交给这个注册的 Servlet 来处理。registration.addMapping(/);} }传统Java Web项目web.xml配置示例如下 ?xml version1.0 encodingUTF-8? web-app xmlnshttp://java.sun.com/xml/ns/javaeexmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsdversion3.0servletservlet-namedispatcher/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-classinit-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/dispatcher-servlet.xml/param-value/init-paramload-on-startup1/load-on-startup/servletservlet-mappingservlet-namedispatcher/servlet-nameurl-pattern//url-pattern/servlet-mapping/web-app 配置DispatcherServlet所需的bean和其他相关内容 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean classorg.springframework.web.servlet.view.InternalResourceViewResolverproperty nameprefix value/WEB-INF/views//property namesuffix value.jsp//bean!-- 其他配置 -- /beans在Servlet环境中您可以选择以编程方式配置Servlet容器作为替代或与web.xml文件结合使用。 public class MyWebApplicationInitializer implements WebApplicationInitializer {Overridepublic void onStartup(ServletContext servletContext) throws ServletException {// 创建 XmlWebApplicationContext 并注册配置类XmlWebApplicationContext ctx new XmlWebApplicationContext();ctx.setConfigLocation(/WEB-INF/spring/dispatcher-config.xml);// 创建 DispatcherServlet 并注册到 ServletContextDispatcherServlet dispatcherServlet new DispatcherServlet(ctx);//向 ServletContext 中注册了一个名为 app 的 ServletServletRegistration.Dynamic registration servletContext.addServlet(app, dispatcherServlet);//表示在容器启动时就立即初始化并加载这个 Servletregistration.setLoadOnStartup(1);//将这个Servlet映射到根路径(/)。//这意味着当用户访问应用的根路径时例如 http://localhost:8080/容器会将请求交给这个注册的 Servlet 来处理。registration.addMapping(/);} }路径匹配 Servlet API将完整的请求路径公开为requestURI并进一步将其细分为contextPath、servletPath和pathInfo它们的值根据Servlet的映射方式而变化。从这些输入中Spring MVC需要确定用于映射处理程序的查找路径这应该排除contextPath和任何servletMapping前缀(如果适用)。 路径可能包含编码的保留字符如“/”或“;”这些字符在解码后会改变路径的结构这也会导致安全问题。 如果DispatcherServlet被映射为默认的带有“/”或不带“/*”前缀的Servlet并且Servlet容器是4.0那么Spring MVC能够检测Servlet映射类型并避免使用servletPath和pathInfo。幸运的是默认的Servlet映射“/”是一个不错的选择 上述问题在使用PathPatternParser和解析模式时得到解决作为使用AntPathMatcher进行字符串路径匹配的替代方案。PathPatternParser从5.3版开始就可以在Spring MVC中使用并且从6.0版开始默认启用。 拦截器 在 Spring MVC 中您可以使用 HandlerInterceptor 来实现对请求处理过程的拦截和控制。当您希望将特定功能应用于某些请求时这些拦截器非常有用——例如检查主体。 HandlerInterceptor 接口定义了三个方法分别是 preHandle()、postHandle() 和 afterCompletion()它们分别在请求处理之前、请求处理之后以及请求完成之后被调用。 1preHandle(..)方法 在实际处理程序运行之前返回一个布尔值。可以使用此方法中断或继续执行链的处理。当此方法返回true时处理程序执行链继续。当它返回false时则中断执行链不会继续执行后续的拦截器或目标方法。可以用于进行登录验证、权限检查等操作。 2postHandle(..)方法 在处理程序运行之后。可以用于添加公共的模型数据、进行日志记录等操作。 3afterCompletion(..)方法 在整个请求处理完成之后被调用即在视图渲染完毕之后。通常用于进行资源清理操作例如释放资源、记录执行时间等。 示例代码如下 Controller public class MyController {PostMapping(/api)ResponseBodypublic void a(){System.out.println(进来了);/** Output: * 请求前* 进来了* 请求后* 请求完成之后*/} } public class MyHandlerInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println(请求前);return true;}Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println(请求后);}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println(请求完成之后);} } Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns(/api/**) // 需要拦截的路径.excludePathPatterns(/api/login); // 不需要拦截的路径;} }异常 如果在请求映射期间发生异常或从请求处理程序(如Controller)抛出异常则DispatcherServlet将委托给HandlerExceptionResolver bean链来解决异常并提供替代处理这通常是一个错误响应。下表列出了可用的HandlerExceptionResolver实现 SimpleMappingExceptionResolver异常类名和错误视图名之间的映射。对于在浏览器应用程序中呈现错误页非常有用。 示例代码如下 Configuration public class Config {Beanpublic SimpleMappingExceptionResolver simpleMappingExceptionResolver(){SimpleMappingExceptionResolver resolver new SimpleMappingExceptionResolver();// 设置异常映射 可定义不同错误类型条装不同页面Properties exceptionMappings new Properties();exceptionMappings.setProperty(java.lang.RuntimeException, error);exceptionMappings.setProperty(java.lang.NullPointerException, error2);resolver.setExceptionMappings(exceptionMappings);// 设置默认错误视图resolver.setDefaultErrorView(/error);return resolver;} } Controller public class MyController {GetMapping(value /api)public void api(){//测试返回异常跳转错误页面throw new NullPointerException();} }web.xml中声明一个错误页映射。下面的例子展示了如何这样做 error-pagelocation/error/location /error-page当出现异常或响应具有错误状态时Servlet容器在容器内将error分派到配置的URL(例如/error)。然后由DispatcherServlet处理可能将其映射到一个Controller它可以被实现为返回一个带有模型的错误视图名称或呈现一个JSON响应如下面的示例所示 RestController public class ErrorController {RequestMapping(path /error)public MapString, Object handle(HttpServletRequest request) {MapString, Object map new HashMap();map.put(status, request.getAttribute(jakarta.servlet.error.status_code));map.put(reason, request.getAttribute(jakarta.servlet.error.message));return map;} }DefaultHandlerExceptionResolverSpring MVC默认的异常处理器解决Spring MVC引发的异常并将它们映射到HTTP状态代码。 示例代码如下 ControllerAdvice public class MyExceptionHandler extends ResponseEntityExceptionHandler {ExceptionHandler(value { Exception.class })protected ResponseEntityObject handleCustomException(Exception ex, WebRequest request) {String errorMessage entity发生异常 ex.getMessage();return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);} }执行结果 继承了 ResponseEntityExceptionHandler使用 ControllerAdvice 注解将其标记为一个全局异常处理器。自定义方法使用 ExceptionHandler 注解来指定需要处理的异常类型在方法内部我们可以根据具体的业务需求自定义返回的 HTTP 响应。在这个例子中我们调用父类handleExceptionInternal() 方法返回了一个具有自定义消息和状态码的 ResponseEntity 对象。 ResponseStatusExceptionResolver使用ResponseStatus注释解析异常并根据注释中的值将异常映射到HTTP状态码。 示例代码如下 ResponseStatus(value HttpStatus.BAD_REQUEST,reason 自定义错误异常) public class MyException extends RuntimeException{ } Controller public class MyController {GetMapping(value /api)public void api(){throw new MyException();} }执行结果 ExceptionHandlerExceptionResolver通过调用Controller或ControllerAdvice类中的ExceptionHandler方法来解决异常。 示例代码如下 ControllerAdvice public class MyExceptionHandler {ExceptionHandler(Exception.class)public ResponseEntityString handleException(Exception ex) {// 处理异常逻辑 可以根据异常类型、业务需求等进行相应的处理// 返回自定义的响应String errorMessage 发生异常 ex.getMessage();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage);} } Controller public class MyController {GetMapping(value /api)public void api(){throw new NullPointerException(空指针错误);} }执行结果 您可以通过在Spring配置中声明多个HandlerExceptionResolver bean并根据需要设置它们的顺序属性来形成异常解析器链。order属性越高异常解析器的位置就越靠后。 Configuration public class ExceptionResolverConfig {Beanpublic HandlerExceptionResolver myExceptionResolver() {MyExceptionResolver resolver new MyExceptionResolver();resolver.setOrder(1); // 设置执行顺序为1return resolver;}Beanpublic HandlerExceptionResolver anotherExceptionResolver() {AnotherExceptionResolver resolver new AnotherExceptionResolver();resolver.setOrder(2); // 设置执行顺序为2return resolver;} }HandlerExceptionResolver的契约规定它可以返回 指向错误视图的ModelAndView。如果在解析器中处理异常则为空ModelAndView。如果异常仍然无法解决则为null供后续解析器尝试如果异常仍然存在则允许它冒泡到Servlet容器中。 MVC配置自动为默认Spring MVC异常、ResponseStatus注释异常和ExceptionHandler方法的支持声明内置解析器。您可以自定义该列表或替换它。 示例代码如下 ControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(NotFoundException.class)public ModelAndView handleNotFoundException(NotFoundException ex) {ModelAndView modelAndView new ModelAndView(error404);modelAndView.addObject(message, ex.getMessage());return modelAndView;}ExceptionHandler(Exception.class)public ModelAndView handleException(Exception ex) {ModelAndView modelAndView new ModelAndView(error500);modelAndView.addObject(message, ex.getMessage());return modelAndView;} }上述代码使用注解的方式定义不同错误类型跳转不同页面这样的好处就是提高代码阅读性。 视图解析 Spring MVC定义了ViewResolver和View允许您在浏览器中呈现模型的界面而不会将您束缚于特定的视图技术。ViewResolver提供视图名称和实际视图之间的映射。View在移交给特定的视图技术之前解决数据准备问题。 以下是几个常用的 ViewResolver 实现类 UrlBasedViewResolver用于解析基于 URL 的视图。它会根据配置的前缀和后缀将逻辑视图名称转换为完整的 URL。例如逻辑视图名称为 redirect:/home则最终的视图为重定向到 /home 的 URL。 示例代码如下 Configuration public class WebConfig {Beanpublic UrlBasedViewResolver viewResolver() {UrlBasedViewResolver resolver new UrlBasedViewResolver();// 设置视图类resolver.setViewClass(JstlView.class);// 设置前缀和后缀resolver.setPrefix(/WEB-INF/views/);resolver.setSuffix(.jsp);return resolver;} }JstlView.class 是 Spring 框架中的一个视图类用于解析 JSP 页面并渲染视图。在使用 JSP 技术时可以使用 JstlView 来渲染 JSP 视图。 InternalResourceViewResolver用于解析 JSP 视图。它会根据配置的前缀和后缀将逻辑视图名称转换为 JSP 文件路径。例如逻辑视图名称为 home配置的前缀为 /WEB-INF/views/后缀为 .jsp则最终的视图路径为 /WEB-INF/views/home.jsp。 示例代码如下 Configuration public class WebConfig {Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver resolver new InternalResourceViewResolver();// 设置视图类resolver.setViewClass(JstlView.class); 、 // 设置前缀和后缀resolver.setPrefix(/WEB-INF/views/);resolver.setSuffix(.jsp);return resolver;} }FreeMarkerViewResolver用于解析 FreeMarker 模板视图。它会根据配置的前缀和后缀将逻辑视图名称转换为 FreeMarker 模板文件路径。 示例代码如下 Configuration public class WebConfig {Beanpublic FreeMarkerViewResolver viewResolver() {FreeMarkerViewResolver resolver new FreeMarkerViewResolver();// 设置前缀和后缀resolver.setPrefix(/WEB-INF/views/);resolver.setSuffix(.ftl);// 设置视图类resolver.setViewClass(FreeMarkerView.class); return resolver;} }我们通过 resolver.setViewClass(FreeMarkerView.class) 设置视图类为 FreeMarkerView以告知 Spring MVC 使用 FreeMarker 引擎来渲染模板视图。 BeanNameViewResolverSpring MVC 中一个特殊的视图解析器它会根据视图名称查找对应的 View 实例。与其他视图解析器不同BeanNameViewResolver 不依赖于视图文件或模板而是通过访问 Spring 容器中的 bean 来返回相应的视图。 示例代码如下 Configuration public class WebConfig {Beanpublic BeanNameViewResolver viewResolver() {BeanNameViewResolver resolver new BeanNameViewResolver();return resolver;} } Component(myView) public class MyView implements View {Overridepublic String getContentType() {return text/html;}Overridepublic void render(MapString, ? model, HttpServletRequest request, HttpServletResponse response) throws Exception {} }通过 BeanNameViewResolver 创建一个视图解析器。BeanNameViewResolver 将会找到名为 myView 的 Bean并将其作为视图进行渲染。 ContentNegotiatingViewResolver用于根据请求的媒体类型如 Accept 头部选择合适的视图来进行内容协商。它可以根据请求的媒体类型将控制器方法返回的模型数据渲染到不同的视图上以满足客户端的需求。 示例代码如下 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.defaultContentType(MediaType.APPLICATION_JSON).mediaType(json, MediaType.APPLICATION_JSON).mediaType(xml, MediaType.APPLICATION_XML);}Beanpublic ContentNegotiatingViewResolver contentNegotiatingViewResolver() {ContentNegotiatingViewResolver resolver new ContentNegotiatingViewResolver();// 设置视图解析器列表ListViewResolver resolvers new ArrayList();// 添加其他视图解析器如 InternalResourceViewResolver、FreeMarkerViewResolver 等resolvers.add(internalResourceViewResolver());resolvers.add(freeMarkerViewResolver());resolver.setViewResolvers(resolvers);return resolver;} }ContentNegotiatingViewResolver本身不解析视图而是委托给其他视图解析器并选择与客户端请求的表示相似的视图。表示形式可以从Accept报头或查询参数(例如/path?formatpdf)确定。 您可以通过声明多个解析器bean来链接视图解析器如果有必要还可以通过设置order属性来指定顺序。记住order属性越高视图解析器在链中的位置就越靠后。 重定向 视图名称中的特殊redirect:前缀允许您执行重定向。UrlBasedViewResolver(及其子类)将此识别为需要重定向的指令。视图名称的其余部分是重定向URL。 Controller public class MyController {GetMapping(value /api)public String api(){return redirect:http://www.baidu.com;} }最终效果与控制器返回了RedirectView相同但现在控制器本身可以根据逻辑视图名称进行操作。逻辑视图名称(如redirect:/myapp/some/resource)相对于当前Servlet上下文重定向而名称(如redirect:https://myhost.com/some/arbitrary/path)重定向到绝对URL。 转发 你也可以为最终由UrlBasedViewResolver和子类解析的视图名使用一个特殊的forward:前缀。 Controller public class MyController {GetMapping(value /api)public String api(){return forward:page;}RequestMapping(value /page)public String page() {return defaultError;} }转发是在服务器内部完成的请求从一个控制器或处理方法直接转发到另一个控制器或处理方法客户端浏览器感知不到这个过程URL 不会发生变化。而重定向是通过发送一个新的HTTP请求给客户端浏览器然后由浏览器重新发起该请求到新的URLURL会发生变化。 转发可以在请求之间共享数据而重定向不能直接在请求之间共享数据。参数传递可以通过HttpServletRequest对象的setAttribute()方法将参数设置到请求属性中然后在转发的目标控制器或处理方法中获取该属性值。示例代码如下 Controller public class MyController {GetMapping(value /api)public String api(HttpServletRequest request){request.setAttribute(param,1);return forward:page;}RequestMapping(value /page)public String handle(HttpServletRequest request) {Object attribute request.getAttribute(param);System.out.println(attribute);return defaultError;} }语言环境 Spring架构的大多数部分都支持国际化就像Spring web MVC框架一样。当一个请求进来时DispatcherServlet寻找一个语言环境解析器如果找到了它就尝试使用它来设置语言环境。通过使用RequestContext.getLocale()方法您总是可以检索由语言环境解析器解析的语言环境。 Controller public class MyController {GetMapping(value /api)public void api(HttpServletRequest request){Locale locale request.getLocale();System.out.println(locale.getDisplayCountry());System.out.println(locale.getCountry());System.out.println(locale.getDisplayName());System.out.println(locale.getDisplayLanguage());/** Output:* 中国* CN* 中文 (中国)* 中文*/} }Cookie解析器 通过使用该区域设置解析器的属性您可以指定cookie的名称以及最长使用时间。下面的例子定义了一个CookieLocaleResolver Configuration public class WebConfig {Beanpublic CookieLocaleResolver localeResolver() {CookieLocaleResolver resolver new CookieLocaleResolver();resolver.setCookieName(myLocaleCookie); // 设置cookie的名称resolver.setCookieMaxAge(3600); // 设置cookie的最长期限单位为秒return resolver;} }Session解析器 相比CookieLocaleResolver该策略将本地选择的语言环境设置存储在Servlet容器的HttpSession。因此这些设置对于每个会话都是临时的因此在每个会话结束时会丢失。 注意它与外部会话管理机制没有直接关系比如Spring Session项目。这SessionLocaleResolver计算并修改相应的HttpSession属性与当前HttpServletRequest。 Configuration public class WebConfig {Beanpublic SessionLocaleResolver localeResolver() {SessionLocaleResolver resolver new SessionLocaleResolver();resolver.setDefaultLocale(Locale.ENGLISH); // 设置默认语言环境return resolver;} }Multipart 解析器 MultipartResolver是一种用于解析多部分请求(包括文件上传)的策略。有一个基于容器的用于Servlet多部分请求解析的StandardServletMultipartResolver实现。 Controller public class MyController {GetMapping(value /api)public void api(HttpServletRequest request){StandardServletMultipartResolver resolver new StandardServletMultipartResolver();if (resolver.isMultipart(request)) {// 将request转换为MultipartHttpServletRequestMultipartHttpServletRequest multipartRequest resolver.resolveMultipart(request);// 获取上传的文件MultipartFile file multipartRequest.getFile(file);// 获取表单中的其他参数String description multipartRequest.getParameter(description);// 处理上传的文件if (file ! null) {String fileName file.getOriginalFilename();try {byte[] bytes file.getBytes();} catch (IOException e) {throw new RuntimeException(e);}// 处理上传的文件数据}// 处理表单中的其他参数}}要启用多部分处理您需要在DispatcherServlet Spring配置中声明一个名为MultipartResolver的MultipartResolver bean。DispatcherServlet检测它并将其应用于传入请求。当接收到内容类型为multipart/form-data的POST时解析器解析将当前HttpServletRequest包装为MultipartHttpServletRequest的内容以提供对已解析文件的访问并将部分作为请求参数公开。 Configuration public class MyWebMvcConfig {Beanpublic StandardServletMultipartResolver standardServletMultipartResolver(){StandardServletMultipartResolver resolver new StandardServletMultipartResolver();return resolver;} }启用MultipartResolver后将解析带有多部分/表单数据的POST请求的内容并将其作为常规请求参数访问。以下示例访问一个常规表单字段和一个上传的文件 Controller public class FileUploadController {PostMapping(/form)public String handleFormUpload(RequestParam(name) String name,RequestParam(file) MultipartFile file) {if (!file.isEmpty()) {byte[] bytes file.getBytes();// store the bytes somewherereturn redirect:uploadSuccess;}return redirect:uploadFailure;} }将参数类型声明为ListMultipartFile允许为同一参数名解析多个文件。 日志 Spring MVC中的调试级日志被设计成紧凑、最小化和人性化的。它专注于反复使用的高价值信息而不是仅在调试特定问题时有用的其他信息。 跟踪级日志记录通常遵循与调试相同的原则(例如也不应该是消防水管)但可以用于调试任何问题。此外一些日志消息在跟踪和调试时可能会显示不同级别的详细信息。 过滤器 spring-web模块提供了一些有用的过滤器数据格式、Forwarded Headers。 格式数据 浏览器只能通过HTTP GET或HTTP POST提交表单数据Servlet API要求ServletRequest.getParameter*()方法只支持HTTP POST的表单字段访问。 FormContentFilter来拦截内容类型为application/x-www-form-urlencoded的HTTP PUT、PATCH和DELETE请求从请求体中读取表单数据并包装ServletRequest使表单数据通过ServletRequest. getparameter *()系列方法可用。 Controller public class MyController {PostMapping(value /api)ResponseBodypublic void api(HttpServletRequest request){String name request.getParameter(name);String user request.getParameter(user);} }Forwarded Headers 当请求经过诸如负载平衡器之类的代理时主机、端口和模式可能会发生变化这使得从客户端角度创建指向正确的主机、端口和模式的链接成为一项挑战。 RFC 7239定义了转发的HTTP报头代理可以使用它来提供有关原始请求的信息。 还有其他非标准头包括X-Forwarded-Host, X-Forwarded-Port,X-Forwarded-Proto, X-Forwarded-Ssl以及X-Forwarded-Prefix。 1X-Forwarded-Host该字段用于指示原始请求中的主机名。例如如果请求example.com/resource被发送到代理代理将请求转发到localhost:8080/resource然后是标题为X-Forwarded-Host: example.com可以发送通知服务器原始主机example.com。 X-Forwarded-Host: example.com2X-Forwarded-Port该字段用于指示原始请求中的端口号。 X-Forwarded-Port: 4433X-Forwarded-Proto该字段用于指示原始请求中的协议。 X-Forwarded-Proto: https4X-Forwarded-Ssl该字段用于指示原始请求是否通过SSL进行加密。它可以有两个值on表示通过SSL加密off表示没有通过SSL加密。 X-Forwarded-Ssl: on5X-Forwarded-Prefix该字段用于指示原始请求中的URL前缀。 X-Forwarded-Prefix: /appForwardedHeaderFilter是一个Servlet过滤器它可以修改请求由于应用程序无法知道报头是由代理按预期添加的还是由恶意客户端添加的因此转发的报头需要考虑安全性。这就是为什么信任边界处的代理应该被配置为移除不信任的代理Forwarded来自外部的标题。您还可以配置ForwardedHeaderFilter随着removeOnlytrue在这种情况下它会移除但不使用标头。 带注释的控制器 Spring MVC提供了一个基于注释的编程模型其中Controller和RestController组件使用注释来表达请求映射、请求输入、异常处理等等。以下示例显示了由批注定义的控制器 Controller public class MyController {GetMapping(/hello)public String handle(Model model) {model.addAttribute(message, Hello World!);return index;} }需要注意的是从Spring 4.3版本开始Controller注解的value属性已被废弃推荐使用RequestMapping注解来指定控制器的映射路径。 声明 您可以在Servlet的WebApplicationContext中使用标准的Spring bean定义来定义控制器bean。Controller构造型允许自动检测与Spring在类路径中检测Component类并为它们自动注册bean定义的通用支持一致。它还充当带注释的类的原型指示其作为web组件的角色。 要启用Controller bean的自动检测您可以在Java配置中添加组件扫描如下面的示例所示 Configuration ComponentScan(org.example.web) public class WebConfig {// ... }XML配置 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:phttp://www.springframework.org/schema/pxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packageorg.example.web//beansRestController是一个复合注释它本身带有Controller和ResponseBody的元注释以表明控制器的每个方法都继承了类型级的ResponseBody注释因此直接写入响应体而不是使用HTML模板进行视图解析和呈现。 在某些情况下例如当控制器上标注了Transactional注解时你可能需要使用AOP代理来修饰控制器。特别是对于控制器建议使用基于类的代理。 如果控制器实现了一个接口并且需要AOP代理你可能需要显式地配置基于类的代理。例如在使用EnableTransactionManagement注解启用事务管理时你可以将proxyTargetClass属性设置为true以明确指定使用基于类的代理。示例如下 Configuration EnableTransactionManagement(proxyTargetClass true) public class AppConfig {// 配置其他的Bean }XML配置 tx:annotation-driven proxy-target-classtrue/启用基于类的代理可能会影响性能因此建议仅在需要使用AOP代理时才将其设置为true。 映射请求 您可以使用RequestMapping将请求映射到控制器方法的注释。它有各种属性可以通过URL、HTTP方法、请求参数、头和媒体类型进行匹配。您可以在类级别使用它来表达共享映射或者在方法级别使用它来缩小到特定的端点映射。 还有特定于HTTP方法的快捷方式变体RequestMappingGetMapping、PostMapping、PutMapping、DeleteMapping、PatchMapping RestController RequestMapping(/api) public class MyController {GetMapping(/resource)public String getResource() {// 处理GET请求return Get resource;}PostMapping(/resource)public String createResource() {// 处理POST请求return Create resource;} }RequestMapping可以使用method属性来指定可以处理的HTTP请求方法如果不指定method属性那么该方法将处理所有的HTTP请求方法。 RequestMapping(value /example, method RequestMethod.GET) public String exampleGetMethod() {// 处理GET请求return get_response; }RequestMapping可以使用URL模式映射方法。有两种选择 PathPattern—与URL路径匹配的预解析模式也预解析为PathContainer。这个解决方案是为web使用而设计的可以有效地处理编码和路径参数并高效地进行匹配。 RestController RequestMapping(/api) public class MyController {RequestMapping(path /users/{id})public String getUserById(PathVariable(id) String id) {// 处理根据用户ID获取用户的请求return User: id;}}从请求的URL路径中提取参数可以通过PathVariable例如 RestController RequestMapping(/api) public class MyController {GetMapping(/user/{id})public String getUserById(PathVariable(id) String id) {// 处理根据用户ID获取用户的请求return User: id;} }AntPathMatcher—根据字符串路径匹配字符串模式。这是Spring配置中使用的原始解决方案用于选择类路径、文件系统和其他位置上的资源。它效率较低字符串路径输入对于有效处理编码和URL的其他问题是一个挑战。 RestController RequestMapping(/api) public class MyController {RequestMapping(path /users/*)public String getUsers() {// 处理获取所有用户的请求return All users;} }其中*是通配符可以匹配任意字符。建议使用PathPattern进行URL模式匹配。如果你在其他场景下进行资源选择可以使用AntPathMatcher进行字符串路径模式匹配。 一些示例模式 /resources/ima?e.png-匹配路径段中的一个字符/resources/*.png-匹配路径段中的零个或多个字符/resources/**-匹配多个路径段/projects/{project}/versions-匹配路径段并将其作为变量捕获/projects/{project:[a-z]}/versions-用正则表达式匹配和捕获变量除此之外你还可以在Spring MVC中控制请求和响应的媒体类型 consumes属性用于指定控制器方法可以接受的请求内容类型。它可以限制请求的Content-Type头必须匹配指定的值才能触发该方法。 PostMapping(path /pets, consumes application/json) public void createPet(RequestBody Pet pet) {// 处理创建宠物的请求 }produces属性用于指定控制器方法返回的响应内容类型。它可以限制响应的Content-Type头必须匹配指定的值。 GetMapping(path /pets, produces application/json) public ListPet getPets() {// 处理获取宠物列表的请求return petService.getPets(); }MediaType为常用的媒体类型提供常数例如APPLICATION_JSON_VALUE和APPLICATION_XML_VALUE。 作为RequestMapping的替代方案您还可以使用HttpExchange方法处理请求。这些方法是在HTTP接口上声明的可以通过HttpServiceProxyFactory作为客户端使用也可以由服务器Controller实现。 public interface ExampleHttpService {HttpExchange(method HttpMethod.GET, path /example)String exampleGetMethod();HttpExchange(method HttpMethod.POST, path /example)String examplePostMethod(String requestBody); } public class MyController {public static void main(String[] args) {ExampleHttpService httpService HttpServiceProxyFactory.create(ExampleHttpService.class, http://localhost:8080);String response httpService.exampleGetMethod();System.out.println(response);} }需要spring版本号6以上才能使用。 其它注解 请求参数 RequestParam注解是Spring框架中用于从请求中获取参数的注解通常用于处理HTTP请求中的查询参数query parameter或表单参数form parameter。 GetMapping(/example) public String handleRequest(RequestParam(name) String name, RequestParam(age) int age) { }RequestHeader注解从HTTP请求头中获取值的注解。通常情况下它用于在处理HTTP请求时将请求头中的信息映射到处理方法的参数上。 GetMapping(/example) public String handleRequest(RequestHeader(User-Agent) String userAgent) { }CookieValue注解用于从HTTP请求的Cookie中获取值的注解。 JSESSIONID415A4AC178C59DACE0B2C9CA727CDD84GetMapping(/example) public String handleRequest(CookieValue(JSESSIONID) String jsessionId) { }RequestBody注解用于接收HTTP请求体中的数据的注解。 PostMapping(/example) public String handleRequest(RequestBody User user) { }RequestAttribute注解用于从当前请求的attributes中获取值。 GetMapping(/example) public String handleRequest(RequestAttribute(attributeName) String attributeValue) { }SessionAttribute注解获取会话中存储的属性值。 GetMapping(/user)public String getUserInfo(SessionAttribute(user) User user) {// 处理方法的逻辑}ModelAttribute注解可以将请求参数自动绑定到一个 Java 对象上。 Controller public class UserController {GetMapping(/user)public String getUser(RequestParam(id) Long id, Model model) {// 根据 id 查询用户信息User user userService.getUserById(id);model.addAttribute(user, user);return user;}PostMapping(/user/save)public String saveUser(ModelAttribute(user) User user) {// 处理保存用户信息的逻辑userService.saveUser(user);return redirect:/user?id user.getId();} }返回值 ResponseBody注解告诉Spring框架响应体的返回不是一个视图而是对象数据本身。 GetMapping(/user/{id})ResponseBodypublic User getUser(PathVariable(id) Long id) {User user userService.getUserById(id);return user;}ControllerAdvice 是一个 Spring 框架的注解用于定义全局控制器增强器。它可以用于集中管理和处理多个控制器共享的逻辑例如异常处理、全局数据绑定、全局模型属性等。 ControllerAdvice public class GlobalControllerAdvice {ExceptionHandler(Exception.class)public ModelAndView handleException(Exception ex) {// 处理全局异常ModelAndView modelAndView new ModelAndView();modelAndView.setViewName(error);modelAndView.addObject(errorMessage, ex.getMessage());return modelAndView;} }你也可以使用RestControllerAdvice注解。 类型转换 类型转换中的一个实际问题是空字符串源值的处理。如果该值变为则该值被视为缺失null作为类型转换的结果。如果你想允许null要被注入要么使用required标志或者将参数声明为Nullable。 PostMappingpublic void createUser(RequestBody Nullable User user) {}矩阵变量 矩阵变量可以出现在任何路径段中每个变量用分号分隔多个值用逗号分隔(例如/cars;colorred,green;year2012).也可以通过重复的变量名指定多个值(例如colorred;colorgreen;colorblue)。 GetMapping(/hello/{id}) ResponseBody public void hello(PathVariable(id) String id, MatrixVariable(name param, required false) String param) {System.out.println(id);System.out.println(param); }在上面的示例中{id}表示路径变量而param表示矩阵变量。没有提供param矩阵变量那么param方法参数将为null。你可以发送以下请求来调用hello方法 GET /hello/123;paramvalueFlash属性 闪存属性为一个请求提供了一种方法来存储要在另一个请求中使用的属性。这是重定向时最常见的需要例如Post-Redirect-Get模式。闪存属性在重定向之前被临时保存(通常在会话中),以便在重定向之后可用于请求并且被立即移除。 GetMapping(/login) public String login(RedirectAttributes redirectAttributes) {redirectAttributes.addFlashAttribute(message, Login successful!);return redirect:/dashboard; }GetMapping(/dashboard) public String dashboard(Model model) {return dashboard; }在上面的代码中login()方法将重定向参数 message: Login successful! 添加到 FlashMap 中并使用 redirect:/dashboard 进行重定向。在 dashboard() 方法中可以使用 Model 来访问这个重定向参数 flash属性的概念存在于许多其他web框架中并且已经证明有时会暴露于并发问题。这是因为根据定义闪存属性将存储到下一次请求。然而“下一个”请求可能不是预期的接收者而是另一个异步请求(例如轮询或资源请求)在这种情况下闪存属性被过早地移除。 InitBinder InitBinder 注解用于初始化 Web 数据绑定器可以用来定制数据绑定过程。通常情况下它用于注册自定义的属性编辑器以便将请求参数转换为控制器方法所需的对象类型。 Controller public class UserController {InitBinderpublic void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat new SimpleDateFormat(yyyy-MM-dd);dateFormat.setLenient(false);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));}PostMapping(/user/save)public String saveUser(ModelAttribute(user) User user) {// 保存用户信息的逻辑userService.saveUser(user);return redirect:/user;} }在这个例子中我们创建了一个 SimpleDateFormat 对象并将其注册为处理 Date 类型的参数。这样做可以确保当控制器方法接收到日期类型的参数时能够正确地进行数据绑定。 验证 Validated是一个 Spring 框架的注解用于在控制器方法参数上启用参数校验。它可以与 javax.validation 标准规范中的注解一起使用例如 NotNull、Size、Pattern 等用于对方法参数进行验证。 public class User {NotNullprivate String name;Min(18)private int age;// getter setter ... } RestController public class MyController {PostMapping(/data)public ResponseEntityString processData(RequestBody Valid DataObject data) {// 处理数据return ResponseEntity.ok(Data processed successfully);} }功能性端点 Spring Web MVC包括WebMvc.Fn是一种轻量级的函数式编程模型其中函数用于路由和处理请求契约被设计为不变性。它是基于注释的编程模型的替代方案但运行在相同的DispatcherServlet上。它可以作为一个 Lambda 表达式或方法引用传递给 Spring WebFlux 框架中的路由定义用于定义在特定请求路径下执行的处理程序。 RouterFunction相当于RequestMapping注释但主要区别在于路由器功能不仅提供数据还提供行为。RouterFunctions.route()提供有助于创建路由器的路由器生成器如下例所示 RouterFunctionServerResponse build RouterFunctions.route().GET(/hello, request - ServerResponse.ok().body(BodyInserters.fromValue(Hello World!))).build();ServerRequest和ServerResponse是不可变的接口提供对HTTP请求和响应的JDK 8友好访问包括头、主体、方法和状态代码。 服务器请求 ServerRequest提供对HTTP方法、URI、标头和查询参数的访问而对正文的访问通过body方法。 获取路径参数假设请求的路径为 /users/{id}则可以使用 pathVariable() 方法提取路径中的 {id} 参数。 String id request.pathVariable(id);获取查询参数返回一个 MultiValueMap 对象。可以使用 get() 方法来获取特定参数名的参数值。 MultiValueMapString, String queryParams request.queryParams(); ListString names queryParams.get(name);获取表单参数获取表单参数。 MonoMultiValueMapString, String formData request.formData(); MonoString username formData.map(data - data.getFirst(username));服务器响应 ServerResponse提供对HTTP响应的访问因为它是不可变的所以您可以使用build方法来创建它。您可以使用生成器来设置响应状态、添加响应标题或提供正文。 创建一个包含JSON内容的200 (OK)响应 ServerResponse response ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).build();创建一个带有响应体的响应 String message Hello, World!; ServerResponse response ServerResponse.ok().bodyValue(message);创建一个自定义状态码的响应 ServerResponse response ServerResponse.status(HttpStatus.CREATED).build();创建一个异常响应 ServerResponse response ServerResponse.status(HttpStatus.NOT_FOUND).bodyValue(Resource not found);添加其他响应头或响应体 ServerResponse response ServerResponse.ok().header(Content-Type, application/json).bodyValue({\message\: \Hello, World!\});完整示例代码如下 Configuration public class Config {Beanpublic RouterFunctionServerResponse route(MyHandler handler) {return RouterFunctions.route().GET(/hello, handler::handleRequest).build();} } Component public class MyHandler {public MonoServerResponse handleRequest(ServerRequest request) {// 处理请求逻辑String name request.queryParam(name).orElse(Anonymous);String message Hello, name !;// 构建响应return ServerResponse.ok().body(BodyInserters.fromValue(message));}public MonoServerResponse handleNotFound(ServerRequest request) {return ServerResponse.status(HttpStatus.NOT_FOUND).build();} }在配置类中使用 Bean 注解定义了一个 RouterFunctionServerResponse 类型的 bean请求/hello路径时会将请求映射到相应的处理器方法。在处理器类中定义了一个 handleRequest() 方法用于处理请求逻辑。 URI Links UriComponentsBuilder帮助从带有变量的URI模板中构建URI如下面的例子所示 public static void main(String[] args) {UriComponents uriComponents UriComponentsBuilder.newInstance().scheme(http)//协议.host(example.com)//主机.path(/api/users)//路径.queryParam(name, john)//参数.queryParam(age, 30).fragment(section-1)//片段通常用于指定文档内的特定位置或锚点.build();String uri uriComponents.toUriString();System.out.println(uri);/** Output:* http://example.com/api/users?namejohnage30#section-1*/}UriComponentsBuilder实现了UriBuilder。反过来你可以用UriBuilderFactory创建一个UriBuilder。您可以使用UriBuilderFactory配置RestTemplate和WebClient来定制URL的准备。 配置RestTemplate的示例如下 public class RestTemplateExample {public static void main(String[] args) {UriBuilderFactory uriBuilderFactory new DefaultUriBuilderFactory(http://example.com);RestTemplate restTemplate new RestTemplate();restTemplate.setUriTemplateHandler(uriBuilderFactory);// 使用 RestTemplate 发起请求...} }配置 WebClient public static void main(String[] args) {UriBuilderFactory uriBuilderFactory new DefaultUriBuilderFactory(http://example.com);WebClient webClient WebClient.builder().uriBuilderFactory(uriBuilderFactory).build();// 使用 WebClient 发起请求...}另外你也可以直接使用DefaultUriBuilderFactory。 String baseUrl https://example.com; DefaultUriBuilderFactory uriBuilderFactory new DefaultUriBuilderFactory(baseUrl);URI uri uriBuilderFactory.uriString(/hotels/{hotel}).queryParam(q, {q}).build(Westin, 123);UriComponentsBuilder在两个级别公开编码选项 UriComponentsBuilder#encode():首先对URI模板进行预编码然后在扩展时对URI变量进行严格编码。UriComponents#encode():编码URI组件在…之后URI变量被扩展。 这两个选项都用转义的八位字节替换非ASCII字符和非法字符。但是第一个选项也会替换URI变量中出现的具有保留含义的字符。 public static void main(String[] args) {URI uri UriComponentsBuilder.fromPath(/hotel list/{city}).queryParam(q, {q}).encode().buildAndExpand(New York, foobar).toUri();System.out.println(uri);/** Output:* /hotel%20list/New%20York?qfoo%2Bbar*/}您可以通过直接转到URI(这意味着编码)来缩短前面的示例 public static void main(String[] args) {URI uri UriComponentsBuilder.fromPath(/hotel list/{city}).queryParam(q, {q}).build(New York, foobar);//或者这样URI uri UriComponentsBuilder.fromUriString(/hotel list/{city}?q{q}).build(New York, foobar);System.out.println(uri);/** Output:* /hotel%20list/New%20York?qfoo%2Bbar*/}WebClient和RestTemplate通过在内部扩展和编码URI模板UriBuilderFactory策略。两者都可以配置自定义策略如下例所示 public static void main(String[] args) {String baseUrl https://example.com;DefaultUriBuilderFactory factory new DefaultUriBuilderFactory(baseUrl)factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.TEMPLATE_AND_VALUES);// Customize the RestTemplate..RestTemplate restTemplate new RestTemplate();restTemplate.setUriTemplateHandler(factory);// Customize the WebClient..WebClient client WebClient.builder().uriBuilderFactory(factory).build();}RestTemplate设置为EncodingMode.URI_COMPONENT出于历史原因和向后兼容性。WebClient依赖于中的默认值DefaultUriBuilderFactory已由更改为EncodingMode.URI_COMPONENT在5.0.x到EncodingMode.TEMPLATE_AND_VALUES在5.1中。 DefaultUriBuilderFactory实施用途UriComponentsBuilder在内部扩展和编码URI模板。作为一个工厂它提供了一个单一的位置来配置编码方法基于以下编码模式之一 TEMPLATE_AND_VALUES用途UriComponentsBuilder#encode()对应于前面列表中的第一个选项对URI模板进行预编码并在扩展时对URI变量进行严格编码。 VALUES_ONLY不对URI模板进行编码而是通过对URI变量进行严格编码UriUtils#encodeUriVariables然后将它们扩展到模板中。 URI_COMPONENT用途UriComponents#encode()对应于前面列表中的第二选项对URI分量值进行编码在…之后URI变量被扩展。 NONE不应用任何编码。 Spring MVC提供了一种机制来准备到控制器方法的链接。 Controller public class MyController {PostMapping(value /api/{id})ResponseBodypublic void api(PathVariable String id) {System.out.println(进来了);}GetMapping(value /hello2)ResponseBodypublic void hello() {UriComponents api MvcUriComponentsBuilder.fromMethodName(MyController.class, api, 21).build();System.out.println(api.toUriString());/** Output:* http://localhost:8088/api/21*/} }我们使用 fromMethodName() 方法指定了 MyController类和 api方法并传递了id参数值为 1。然后我们可以通过调用 build() 构建URL。 异步请求 DeferredResult和Callable控制器方法中的返回值为单个异步返回值提供了基本支持。 DeferredResult Spring MVC 提供的一种异步处理机制。它是一个持有异步处理结果的容器可以在处理请求时返回一个 DeferredResult 对象然后在另一个线程中处理异步任务并将结果设置到 DeferredResult 对象中最终返回给客户端。 RestController public class MyController {GetMapping(/task)public DeferredResultString handleTask() {DeferredResultString deferredResult new DeferredResult();// 在另一个线程中执行异步任务CompletableFuture.supplyAsync(() - {// 执行异步任务String result doSomething();return result;}).whenCompleteAsync((result, throwable) - {if (throwable ! null) {deferredResult.setErrorResult(throwable.getMessage());} else {deferredResult.setResult(result);}});return deferredResult;}private String doSomething() {// 执行异步任务的逻辑return task result;} }使用 DeferredResult 还可以处理一些特殊的场景例如长时间的计算任务、文件上传等。 Callable Callable 是 Java 并发编程中的一个接口用于表示一个可并发执行的任务。 Controller public class MyController {GetMapping(value /task)ResponseBodypublic CallableString task() {return ()- doSomething();}private String doSomething() {try {Thread.sleep(10000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 执行异步任务的逻辑return task result;} }如果您想生成多个异步值并将它们写入响应您可以使用ResponseBodyEmitter返回值以产生对象流其中每个对象都用HttpMessageConverter并写入响应如下例所示 Controller public class MyController {GetMapping(value /task)ResponseBodypublic ResponseBodyEmitter task() {ResponseBodyEmitter responseBodyEmitter new ResponseBodyEmitter();new Thread(()-{try {for (int i 0; i 10; i) {responseBodyEmitter.send(i);Thread.sleep(1000);}responseBodyEmitter.complete(); // 发送完成事件} catch (Exception e) {responseBodyEmitter.completeWithError(e); // 发送错误事件}}).start();/** Output:* 0123456789*/return responseBodyEmitter;} }当一个emitter抛出一个IOException(例如如果远程客户端离开了)应用程序不负责清理连接也不应该调用emitter.complete()或者emitter.completeWithError()。 SSE SSE 是一种基于 HTTP 协议的服务器推送技术允许服务器向客户端发送异步的、持久化的消息流。其中从服务器发送的事件根据W3C SSE规范进行格式化。 Controller public class MyController {GetMapping(value /task)ResponseBodypublic SseEmitter task() {SseEmitter sseEmitter new SseEmitter();// 在新线程中生成事件和数据并发送给客户端new Thread(() - {try {for (int i 0; i 10; i) {SseEmitter.SseEventBuilder event SseEmitter.event().id(String.valueOf(i)).data(Data i).comment(Comment i);sseEmitter.send(event);Thread.sleep(1000);}sseEmitter.complete(); // 发送完成事件} catch (Exception e) {sseEmitter.completeWithError(e); // 发送错误事件}}).start();return sseEmitter;} }客户端可以通过使用 JavaScript 中的 EventSource 对象来接收服务器发送的 SSE 事件和数据。例如 const eventSource new EventSource(/stream);eventSource.onmessage function(event) {console.log(event.data); };eventSource.onerror function(event) {console.error(Error:, event); };eventSource.onopen function() {console.log(Connection opened.); };eventSource.onclose function() {console.log(Connection closed.); };当远程客户端离开时Servlet API不提供任何通知。因此在流式传输到响应时无论是通过SseEmitter还是响应类型定期发送数据是很重要的因为如果客户端已断开连接则写入将失败。发送可以采用空(仅注释)SSE事件的形式也可以是另一方必须将其解释为心跳而忽略的任何其他数据。 或者考虑使用具有内置心跳机制的web消息传递解决方案(例如STOMP over WebSocket或WebSocket with SockJS)。 CORS 跨域资源共享(Cross-Origin Resource Sharing, CORS)是由大多数浏览器实现的W3C规范它允许您指定授权哪种跨域请求而不是使用基于IFRAME或JSONP的不太安全且功能不太强大的解决方案。 要实现跨域访问需要在服务端设置响应头信息。具体来说需要在响应头中添加以下信息 //允许访问的源地址 Access-Control-Allow-Origin: https://example.com //允许访问的 HTTP 方法 Access-Control-Allow-Methods: GET, POST, PUT, DELETE //允许访问的请求头字段 Access-Control-Allow-Headers: Content-Type //缓存预检请求的时间单位秒 Access-Control-Max-Age: 3600 //是否允许发送 Cookie Access-Control-Allow-Credentials: trueSpring MVC HandlerMapping实现提供了对CORS的内置支持。为了启用跨来源请求(即Origin头存在并且不同于请求的主机)您需要有一些显式声明的CORS配置。如果没有找到匹配的CORS配置飞行前请求将被拒绝。 您可以在中组合全局CORS配置HandlerMapping更细粒度的处理程序级CORS配置。例如带注释的控制器可以使用类级或方法级CrossOrigin注释(其他处理程序可以实现CorsConfigurationSource). 组合全局和本地配置的规则通常是相加的例如所有全局和所有本地起源。对于那些只能接受单个值的属性例如allowCredentials和maxAge局部值会覆盖全局值。 RestController public class MyController {CrossOrigin(origins https://example.com, maxAge 3600)GetMapping(/data)public MapString, Object getData() {// ...}}在上述示例中我们在控制器方法也可以在类上添加了 CrossOrigin 注解指定了允许访问的来源地址和缓存预检请求的时间。 allowCredentials默认情况下不启用因为这将建立一个公开敏感的用户特定信息(如cookies和CSRF令牌)的信任级别并且只应在适当的时候使用。当它被启用时allowOrigins必须设置为一个或多个特定域(但不是特殊值*)或者allowOriginPatterns属性可用于匹配一组动态原点。 除了细粒度的控制器方法级配置您可能还想定义一些全局CORS配置您可以使用CorsRegistry回调。 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping(/index/**)//开启跨域的接口路径,使用了 /** 通配符表示所有以 /index/ 开头的接口都需要开启跨域访问。.allowedOrigins(http://example.com)//允许跨域访问的来源地址。.allowedMethods(GET, POST)//允许的请求方法。.allowedHeaders(*)//允许的请求头。.allowCredentials(true)//开启了跨域请求的 Cookie 支持.maxAge(3600);// 使用 maxAge 方法设置了响应缓存的时间以提高跨域请求的性能。}转换为XML配置 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:mvchttp://www.springframework.org/schema/mvcxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdmvc:corsmvc:mapping path/index/**/mvc:allowed-originsmvc:originhttp://example.com/mvc:origin/mvc:allowed-originsmvc:allowed-methodsmvc:methodGET/mvc:methodmvc:methodPOST/mvc:method/mvc:allowed-methodsmvc:allowed-headersmvc:header*/mvc:header/mvc:allowed-headersmvc:allow-credentialstrue/mvc:allow-credentialsmvc:max-age3600/mvc:max-age/mvc:cors/beans你可以通过内置的CorsFilter应用CORS支持。 Configuration public class Config {Beanpublic CorsFilter corsFilter() {//创建了一个 CorsConfiguration 对象并设置了允许携带凭证、允许的来源、请求头和请求方法。CorsConfiguration corsConfig new CorsConfiguration();corsConfig.setAllowCredentials(true);corsConfig.addAllowedOrigin(http://example.com);corsConfig.addAllowedHeader(*);corsConfig.addAllowedMethod(GET);corsConfig.addAllowedMethod(POST);//将 CorsConfiguration 对象注册到路径为 /index/** 的 URL 上。UrlBasedCorsConfigurationSource corsConfigSource new UrlBasedCorsConfigurationSource();corsConfigSource.registerCorsConfiguration(/index/**, corsConfig);// 创建 CorsFilter 对象return new CorsFilter(corsConfigSource);} }HTTP缓存 HTTP缓存可以显著提高web应用程序的性能。 Controller public class MyController {GetMapping(/index)public ResponseEntityString index(){String data hello world; 创建 CacheControl 对象设置缓存时间为 1 小时CacheControl cacheControl CacheControl.maxAge(1, TimeUnit.HOURS);return ResponseEntity.ok().cacheControl(cacheControl).body(data);} }我们创建了一个 CacheControl 对象并使用 maxAge() 方法设置了最大缓存时间为 60 分钟。然后在返回 ResponseEntity 对象时使用 cacheControl() 方法将 CacheControl 对象添加到响应头部中。 当客户端收到响应时就可以看到 Cache-Control: max-age3600 字段表示客户端可以将该响应缓存 60 分钟。 视图技术 在Spring MVC中使用视图技术是可扩展的。决定使用Thymeleaf、Groovy Markup Templates、jsp还是其他技术主要是一个配置更改问题。视图可以访问应用程序上下文的所有bean。因此不建议在模板可由外部源编辑的应用程序中使用Spring MVC的模板支持因为这可能有安全隐患。 Thymeleaf Thymeleaf是一个现代的服务器端Java模板引擎它强调可以通过双击在浏览器中预览的自然HTML模板这对于独立处理UI模板(例如由设计师)非常有帮助而不需要运行服务器。 pom依赖 dependencygroupIdorg.thymeleaf/groupIdartifactIdthymeleaf-spring5/artifactIdversion3.1.2.RELEASE/version/dependency示例代码如下 Controller public class MyController {GetMapping(/index)public ModelAndView index(){User user new User();user.setName(张三);user.setId(1);user.setAge(16);ModelAndView modelAndView new ModelAndView(user);modelAndView.addObject(user,user);return modelAndView;} }html文件 !DOCTYPE html html xmlns:thhttp://www.thymeleaf.org langen headmeta charsetUTF-8titleTitle/title /head body h1 th:text${user.name}Default Page Title/h1 /body /html更多使用方法参考官方文档https://www.thymeleaf.org/。 FreeMarker Apache FreeMarker是一个模板引擎用于生成从HTML到电子邮件和其他任何类型的文本输出。Spring框架内置了使用Spring MVC和FreeMarker模板的集成。 pom依赖 dependencygroupIdorg.freemarker/groupIdartifactIdfreemarker/artifactIdversion2.3.32/version/dependency以下示例显示了如何将FreeMarker配置为视图技术 Configuration EnableWebMvc public class WebConfig implements WebMvcConfigurer {Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.freeMarker();}// Configure FreeMarker...Beanpublic FreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer new FreeMarkerConfigurer();configurer.setTemplateLoaderPath(/WEB-INF/freemarker);return configurer;} }SpringBoot可以在 application.properties或 application.yml文件中配置 FreeMarker 的相关属性 spring.freemarker.template-loader-pathclasspath:/templates/ spring.freemarker.charsetUTF-8示例代码如下 Controller public class MyController {GetMapping(/index)public String index(Model model){User user new User();user.setName(张三);user.setId(1);user.setAge(16);model.addAttribute(user,user);return index;} }.ftl文件 !DOCTYPE html html langen headmeta charsetUTF-8titleTitle/title /head body h1${user.name}/h1 /body /html更多使用参考官方文档https://freemarker.apache.org/。 除此之外Spring框架有一个内置的集成可以将Spring MVC与任何可以在JSR-223 Java脚本引擎。比如Handlebars、Mustache、React、EJS、ERB、String templates、Kotlin Script templating。 JSP和JSTL Spring框架有一个内置的集成可以将Spring MVC与JSP和JSTL结合使用。 示例代码如下 Controller public class HomeController {GetMapping(/user/info)public String userInfo(Model model) {String name Tom;int age 20;model.addAttribute(name, name);model.addAttribute(age, age);return userInfo;} }在 src/main/webapp/WEB-INF/views/ 目录下创建 index.jsp 文件以下是一个使用 JSP 和 JSTL 的示例代码 % taglib urihttp://java.sun.com/jsp/jstl/core prefixc % !DOCTYPE html html headmeta charsetUTF-8titleJSTL 示例/title /head bodyc:set varname valueTom/c:set varage value20/c:if test${age 18}p${name}已经成年了。/p/c:ifc:choosec:when test${age 20}p${name}已经超过20岁了。/p/c:whenc:otherwisep${name}还没有超过20岁。/p/c:otherwise/c:chooseulc:forEach vari begin1 end5li${i}/li/c:forEach/ul /body /htmlSpringBoot默认是不支持JSP PDF和Excel Spring使得从模型数据动态生成PDF文档或Excel电子表格变得简单。文档是视图并从服务器以正确的内容类型流式传输以(希望)使客户端PC能够运行他们的电子表格或PDF查看器应用程序作为响应。 为了使用Excel视图需要将Apache POI库添加到您的类路径中。 dependencygroupIdorg.apache.poi/groupIdartifactIdpoi/artifactIdversion5.2.5/version/dependencydependencygroupIdorg.apache.poi/groupIdartifactIdpoi-ooxml/artifactIdversion5.2.5/version/dependency示例代码如下 Controller public class MyController {GetMapping(/report)ResponseBodypublic String report(HttpServletResponse response) {try {// 创建一个空的工作簿对象Workbook workbook new XSSFWorkbook();// 创建一个工作表对象Sheet sheet workbook.createSheet(My Sheet);// 添加数据Row row1 sheet.createRow(0);Cell cell1 row1.createCell(0);cell1.setCellValue(Name);Row row2 sheet.createRow(1);Cell cell2 row2.createCell(0);cell2.setCellValue(John Doe);Row row3 sheet.createRow(2);Cell cell3 row3.createCell(0);cell3.setCellValue(Jane Doe);// 设置响应头response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet);response.setHeader(Content-disposition, attachment; filenametest.xlsx);// 将工作簿写入到输出流中ServletOutputStream outputStream response.getOutputStream();workbook.write(outputStream);outputStream.close();System.out.println(Excel文件已创建);} catch (Exception e) {e.printStackTrace();}return index;} }对于PDF生成您需要添加(最好)OpenPDF库。 dependencygroupIdcom.github.librepdf/groupIdartifactIdopenpdf/artifactIdversion1.3.35/version/dependency示例代码如下 import com.lowagie.text.Document; import com.lowagie.text.Paragraph; import com.lowagie.text.pdf.PdfWriter; Controller public class MyController {GetMapping(/report)ResponseBodypublic String report(HttpServletResponse response) {try {// 创建一个空白的PDF文档对象Document document new Document();response.setHeader(Content-disposition, attachment; filenametest.pdf);// 创建PdfWriter对象将文档对象写入到一个输出流中PdfWriter.getInstance(document, response.getOutputStream());// 打开文档对象document.open();// 添加一段文字到文档中document.add(new Paragraph(Hello, World!));// 关闭文档对象document.close();} catch (Exception e) {e.printStackTrace();}return index;} }Jackson Jackson是一个流行的Java库用于处理JSON数据。它提供了一组功能强大的API可用于将Java对象序列化为JSON格式以及将JSON数据反序列化为Java对象。 public class User {private Integer id;private String name;private String age;//getter setter ... .. Overridepublic String toString() {return idid,namename,ageage;}JSON序列化 public static void main(String[] args) throws JsonProcessingException {User user new User();user.setName(张三);user.setId(1);user.setAge(16);ObjectMapper objectMapper new ObjectMapper();String str objectMapper.writeValueAsString(user);System.out.println(str);/** Output:* {id:1,name:张三,age:16}*/}JSON反序列化 public static void main(String[] args) throws JsonProcessingException {String json {\id\:1,\name\:\张三\,\age\:\16\};ObjectMapper objectMapper new ObjectMapper();User user objectMapper.readValue(json, User.class);System.out.println(user);/** Output:* id1,name张三,age16*/}XML编组 MarshallingView是Spring Framework提供的一个视图类用于将Java对象通过不同的编组器Marshaller序列化为XML、JSON等格式。 public class XmlView extends AbstractView {private final JAXBContext jaxbContext;public XmlView(Class?... classesToBeBound) throws Exception {jaxbContext JAXBContext.newInstance(classesToBeBound);setContentType(application/xml);}Overrideprotected void renderMergedOutputModel(MapString, Object map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {// 从模型中获取Java对象Object object map.get(object);// 创建JAXB编组器Marshaller marshaller jaxbContext.createMarshaller();// 设置编组选项marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//设置编码httpServletResponse.setCharacterEncoding(utf-8);// 将Java对象编组为XML并写入到响应输出流中marshaller.marshal(object, httpServletResponse.getWriter());} } Controller public class MyController {GetMapping(value /toXml, produces application/xml;charsetUTF-8)ResponseBodypublic ModelAndView toXml(HttpServletResponse response) throws Exception {User user new User();user.setName(张三);user.setId(1);user.setAge(16);ModelAndView modelAndView new ModelAndView(new XmlView(User.class));modelAndView.addObject(object,user);return modelAndView;} } XmlRootElement public class User {private Integer id;private String name;private String age;//getter setter ... .. }最终结果如图 XSLT视图 XSLT是XML的一种转换语言作为web应用程序中的一种视图技术很受欢迎。如果您的应用程序自然地处理XML或者如果您的模型可以很容易地转换成XML那么XSLT作为一种视图技术可能是一个不错的选择。 挺麻烦的还得创建完xsl才能进行转换可以使用Apache Cocoon、XStream、eXist-db等工具来处理XML数据。 示例代码如下 public static void main(String[] args) throws Exception {TransformerFactory factory TransformerFactory.newInstance();Source xslt new StreamSource(new FileInputStream(transform.xsl));Transformer transformer factory.newTransformer(xslt);Source xml new StreamSource(new FileInputStream(books.xml));Result result new StreamResult(new FileOutputStream(output.html));transformer.transform(xml, result);}xml文件 !-- books.xml -- librarybooktitleBook 1/titleauthorAuthor 1/author/bookbooktitleBook 2/titleauthorAuthor 2/author/book /libraryxsl文件 !-- transform.xsl -- xsl:stylesheet version1.0 xmlns:xslhttp://www.w3.org/1999/XSL/Transformxsl:template match/htmlbodyh2Books/h2tabletrthTitle/ththAuthor/th/trxsl:for-each selectlibrary/booktrtdxsl:value-of selecttitle//tdtdxsl:value-of selectauthor//td/tr/xsl:for-each/table/body/html/xsl:template /xsl:stylesheet最终生成output.html文件 MVC配置 MVC Java配置和MVC XML名称空间提供了适用于大多数应用程序的默认配置和一个配置API来定制它。 启用MVC配置 在Java配置中您可以使用EnableWebMvc批注来启用MVC配置如下例所示 Configuration EnableWebMvc public class WebConfig { }在XML配置中可以使用mvc:annotation-driven元素来启用MVC配置 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:mvchttp://www.springframework.org/schema/mvcxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsdmvc:annotation-driven//beansMVC配置API 在Java配置中您可以实现WebMvcConfigurer接口如下例所示 Configuration EnableWebMvc public class WebConfig implements WebMvcConfigurer {// Implement configuration methods... }类型转换 默认情况下安装了各种数字和日期类型的格式化程序并支持通过字段上的NumberFormat和DateTimeFormat进行自定义。 要在Java config中注册自定义格式化程序和转换器请使用以下代码 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addFormatters(FormatterRegistry registry) {registry.addFormatter(new CustomDateFormatter());} } public class CustomDateFormatter implements FormatterDate {Overridepublic Date parse(String text, Locale locale) throws ParseException {// 解析日期逻辑SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);return sdf.parse(text);}Overridepublic String print(Date object, Locale locale) {// 格式化日期逻辑SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);return sdf.format(object);} }内容类型 您可以配置Spring MVC如何从请求中确定所请求的媒体类型(例如Accept头、URL路径扩展、查询参数等)。可以使用 configureContentNegotiation() 方法来配置内容协商策略。内容协商是指客户端和服务器之间协商数据传输格式的过程常见的数据格式有 JSON、XML 等。 以下是一个示例代码 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.defaultContentType(MediaType.APPLICATION_JSON);// 设置支持的返回类型configurer.mediaType(json, MediaType.APPLICATION_JSON);configurer.mediaType(xml, MediaType.APPLICATION_XML);} }消息转换器 configureMessageConverters() 方法是用来配置消息转换器的。消息转换器是负责将请求体和响应体中的数据转换成 Java 对象或者其他数据类型的组件。Spring MVC 内置了许多消息转换器可以支持多种数据格式的转换例如 JSON、XML、表单数据等。 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configureMessageConverters(ListHttpMessageConverter? converters) {Jackson2ObjectMapperBuilder builder new Jackson2ObjectMapperBuilder().indentOutput(true)//设置输出的 JSON 格式化时缩进。.dateFormat(new SimpleDateFormat(yyyy-MM-dd))//设置日期格式为 yyyy-MM-dd.modulesToInstall(new ParameterNamesModule());//用于支持方法参数名的序列化和反序列化。//创建的两个消息转换器对象添加到 converters 列表中这样 Spring MVC 就会在处理请求和响应时使用这些消息转换器。converters.add(new MappingJackson2HttpMessageConverter(builder.build()));converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));} }上述代码的作用是配置消息转换器其中包括 JSON 消息转换器和 XML 消息转换器以支持 JSON 和 XML 格式的请求和响应。 视图控制器 addViewControllers()方法 用于注册简单的视图控制器。它可以方便地将路径与视图之间建立映射关系而无需编写完整的控制器代码。 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController(/).setViewName(index);}上述代码表示将根路径 / 映射到名为 index的视图。也就是说当用户访问应用程序的根路径时将返回名为 index 的视图作为响应。 XML配置 mvc:view-controller path/ view-namehome/查看解析器 MVC配置简化了视图解析器的注册。 在Java配置中您可以添加各自的Configurerbean如下例所示 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {//启用了内容协商功能根据请求头中的 Accept 字段自动选择返回 JSON 或 HTML 视图。registry.enableContentNegotiation(new MappingJackson2JsonView());//配置了 FreeMarker 视图解析器并禁用了模板缓存。registry.freeMarker().cache(false);}Beanpublic FreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer new FreeMarkerConfigurer();//设置路径configurer.setTemplateLoaderPath(/freemarker);return configurer;} }静态资源 addResourceHandlers()方法 是 Spring MVC 中的一个方法用于注册静态资源处理器。它可以方便地将路径与静态资源之间建立映射关系从而能够让 Spring MVC 处理并返回静态资源。 Configuration public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(/static/**).addResourceLocations(classpath:/static/);} }上述代码/static/** 路径被映射到了 classpath:/static/ 目录下的静态资源。当用户请求 /static/ 下的任意资源时Spring MVC 将会在 classpath:/static/ 目录下查找相应的资源文件并将其返回给用户。 需要注意的是多次调用 addResourceHandlers()方法可以注册多个静态资源处理器以处理不同的静态资源路径。 默认Servlet configureDefaultServletHandling()方法 是 Spring MVC 中的一个方法用于配置是否将静态资源的请求交给默认的 Servlet 处理。 在某些情况下我们可能希望将某些特定的请求交给默认的 Servlet 处理而不经过 Spring MVC 的 DispatcherServlet。默认的 Servlet 通常由 Web 容器提供它负责处理静态资源请求如图片、CSS 文件、JavaScript 文件等。 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {//启用默认的 Servlet 处理configurer.enable();} }当启用了默认的 Servlet 处理时如果某个请求不能由 Spring MVC 的 DispatcherServlet 处理将会交给默认的 Servlet 处理。这样我们就可以在应用程序中同时使用 Spring MVC 和默认的 Servlet 来处理请求以提供静态资源和动态内容。 路径匹配 在 Spring MVC 中当一个请求到达 DispatcherServlet 后会将其映射到对应的控制器方法上。这个映射过程就需要考虑 URL 的匹配规则以便正确地选择合适的控制器方法来处理请求。 Configuration EnableWebMvc public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix(/api, HandlerTypePredicate.forAnnotation(MyController.class));}private PathPatternParser patternParser() {// ...} }这种配置方式可以实现对特定路径下的请求进行统一处理例如将所有 API 请求都映射到 /api 路径下的控制器类中方便管理和维护。例如其中有一个处理器方法使用 GetMapping(/users) 注解则该方法的完整请求路径应为 /api/users。 高级Java配置 DelegatingWebMvcConfiguration 是 Spring MVC 中的一个配置类它实现了 WebMvcConfigurer 接口并提供了默认的配置。包括处理器映射、视图解析器、消息转换器等。通过继承这个类并重写其中的方法我们可以对默认配置进行修改和补充。 对于高级模式你可以删除EnableWebMvc并直接从DelegatingWebMvcConfiguration扩展如下例所示 Configuration public class CustomWebMvcConfig extends DelegatingWebMvcConfiguration {Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController(/home).setViewName(home);}Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix(/api, HandlerTypePredicate.forAnnotation(RestController.class));}}高级XML配置 BeanPostProcessor 是 Spring 框架中的一个接口它允许在 Spring 容器实例化 Bean 对象之后、初始化之前和销毁之后对 Bean 实例进行一些自定义的处理。 当 Spring IOC 容器创建一个 Bean 的时候在实例化 Bean 和完成依赖注入之后Spring 会检查在容器中是否注册了 BeanPostProcessor 类型的 Bean。如果有则 Spring 会在初始化 Bean 的前后自动调用 BeanPostProcessor 中的两个方法postProcessBeforeInitialization() 和 postProcessAfterInitialization()。 public class MyBeanPostProcessor implements BeanPostProcessor {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(Before initialization of bean beanName);return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(After initialization of bean beanName);return bean;} }其他Web框架 Spring框架的核心价值主张之一是支持选择。一般来说Spring不会强迫您使用或购买任何特定的架构、技术或方法(尽管它肯定会推荐一些而不是其他)。 JSF JavaServer Faces (JSF)是JCP标准的基于组件的、事件驱动的web用户界面框架。它是Jakarta EE保护伞的官方部分但也可以单独使用例如通过在Tomcat中嵌入Mojarra或MyFaces。 Apache Struts Struts由Craig McClanahan发明是一个由Apache软件基金会托管的开源项目。Struts 1.x极大地简化了JSP/Servlet编程范例并赢得了许多使用专有框架的开发人员的支持。简化了编程模型;它是开源的;它有一个庞大的社区这使得项目不断发展并在Java web开发人员中流行起来。 Apache Tapestry Tapestry是一个“面向组件的框架用于在Java中创建动态的、健壮的、高度可伸缩的web应用程序”。 虽然Spring有自己强大的web层但是通过结合使用Tapestry作为web用户界面和Spring容器作为底层来构建企业Java应用程序有许多独特的优势。
http://www.pierceye.com/news/37853/

相关文章:

  • 网站友情链接检测如何实现企业网站推广的系统性
  • 深圳网站建设开发需要多少钱深圳南山网站开发
  • 网站做多久才有流量网站建设厂商
  • 江苏网站制作宁德网站建设维护
  • 查找企业资料的网站wordpress生产app
  • 西宁网站建设君博解决铁岭公司做网站
  • 常州百度网站排名优化文档流程做网站
  • 本地服务类网站成本建设网站如何赚钱
  • 网站备案主体是上街区做网站
  • asp门户网站源码网站建设教程.
  • 商务网站建设实验报告网站建设域名和空间
  • 怎么样做国外推广网站湖南建筑信息网平台
  • 最新网站排名优化方法wordpress floating menu
  • 滕州市 网站建设公司网站开发工程师招聘
  • 昆山建设招标信息网站win7 iis默认网站设置
  • 有什么网站可以做六级题目嘛建设一个网站需要哪些员工
  • 私自建立网站网站判决书报考二级建造师证需要什么条件
  • 网站设计公司 龙岗2345系统导航
  • 徐州做网站最好的公司工程项目建设自学网站
  • 网站改版 百度影响it运维
  • 网站建设403网站怎么建设?
  • 在线做带字头像的网站网站备案是怎么回事
  • 如何推广手机网站公司网站cms
  • 内容类网站如何 流量厦门公司做网站
  • 百度帐号登录班级优化大师是干什么用的
  • 怎样接做网站的活wap手机网站分享代码
  • 集团网站 wordpress邯郸思勤网络科技有限公司
  • 国内做服装的网站有哪些网站模板备份
  • 自己电脑做服务器上传网站 需要备案吗Wordpress首页制作代码
  • 易县有没有z做网站的宜宾建设局网站