关于spring-mvc:SpringMVC使用MultipartFile对象实现文件上传

1、增加依赖<!-- https://mvnrepository.com/artifact/commons-fileupload/commonsfileupload --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency>2、在SpringMVC的配置文件中增加配置:<!--必须通过文件解析器的解析能力将文件转换为MultipartFile对象--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>3、控制器办法:@RequestMapping("/testUp")public String testUp(MultipartFile photo, HttpSession session)throws IOException {//获取上传的文件的文件名String fileName = photo.getOriginalFilename();//解决文件重名问题String hzName = fileName.substring(fileName.lastIndexOf("."));fileName = UUID.randomUUID().toString() + hzName;//获取服务器中photo目录的门路ServletContext servletContext = session.getServletContext();String photoPath = servletContext.getRealPath("photo");File file = new File(photoPath);if(!file.exists()){file.mkdir();}String finalPath = photoPath + File.separator + fileName;//实现上传性能photo.transferTo(new File(finalPath));return "success";}

January 5, 2023 · 1 min · jiezi

关于spring-mvc:SpringMVC实现下载功能

@RequestMapping("/test/down") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException { //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的实在门路 String realPath = servletContext.getRealPath("/static/img/123.jpg"); //创立输出流 InputStream is = new FileInputStream(realPath); //创立字节数组 byte[] bytes = new byte[is.available()]; //将流读到字节数组中 is.read(bytes); //创立HttpHeaders对象设置响应头信息 MultiValueMap<String, String> headers = new HttpHeaders(); //设置要下载方式以及下载文件的名字 headers.add("Content-Disposition","attachment;filename=1.jpg"); //设置响应状态码 HttpStatus statusCode = HttpStatus.OK; //创立ResponseEntity对象 ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers,statusCode); //敞开输出流 is.close(); return responseEntity; }

January 5, 2023 · 1 min · jiezi

关于spring-mvc:SpringMVC常见面试题

1、什么是Spring MVC ?简略介绍下你对springMVC的了解?Spring MVC是一个基于Java的实现了MVC设计模式的申请驱动类型的轻量级Web框架,通过把Model,View,Controller拆散,将web层进行职责解耦,把简单的web利用分成逻辑清晰的几局部,简化开发,缩小出错,不便组内开发人员之间的配合。 2、SpringMVC的流程?(1)用户发送申请至前端控制器DispatcherServlet; (2)DispatcherServlet收到申请后,调用HandlerMapping处理器映射器,申请获取Handler; (3)处理器映射器依据申请url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet; (4)DispatcherServlet 调用 HandlerAdapter处理器适配器,申请执行Handler; (5)HandlerAdapter 通过适配调用 具体处理器进行解决业务逻辑; (6)Handler执行实现返回ModelAndView; (7)HandlerAdapter将Handler执行后果ModelAndView返回给DispatcherServlet; (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析; (9)ViewResolver解析后返回具体View; (10)DispatcherServlet对View进行渲染视图(行将模型数据填充至视图中) (11)DispatcherServlet响应用户。 前端控制器 DispatcherServlet:接管申请、响应后果,相当于转发器,有了DispatcherServlet 就缩小了其它组件之间的耦合度。 处理器映射器 HandlerMapping:依据申请的URL来查找Handler 处理器适配器 HandlerAdapter:负责执行Handler 处理器 Handler:处理器,须要程序员开发 视图解析器 ViewResolver:进行视图的解析,依据视图逻辑名将ModelAndView解析成真正的视图(view) 视图View:View是一个接口, 它的实现类反对不同的视图类型,如jsp,freemarker,pdf等等 3、Springmvc的长处:(1)能够反对各种视图技术,而不仅仅局限于JSP; (2)与Spring框架集成(如IoC容器、AOP等); (3)清晰的角色调配:前端控制器(dispatcherServlet) ,申请到处理器映射(handlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。 (4) 反对各种申请资源的映射策略。 4、SpringMVC怎么样设定重定向和转发的?(1)转发:在返回值后面加"forward:",譬如"forward:user.do?name=method4" (2)重定向:在返回值后面加"redirect:",譬如"redirect:http://www.baidu.com" 5、 SpringMVC罕用的注解有哪些?@RequestMapping:用于解决申请 url 映射的注解,可用于类或办法上。用于类上,则示意类中的所有响应申请的办法都是以该地址作为父门路。 @RequestBody:注解实现接管http申请的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller办法返回对象转化为json对象响应给客户。 6、SpingMvc中的控制器的注解个别用哪个?有没有别的注解能够代替?答:个别用@Controller注解,也能够应用@RestController,@RestController注解相当于@ResponseBody + @Controller,示意是体现层,除此之外,个别不必别的注解代替。 7、springMVC和struts2的区别有哪些?(1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。 (2)springmvc是基于办法开发(一个url对应一个办法),申请参数传递到办法的形参,能够设计为单例或多例(倡议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。 (3)Struts采纳值栈存储申请和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request申请内容解析,并给办法形参赋值,将数据和视图封装成ModelAndView对象,最初又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认应用jstl。 8、如何解决POST申请中文乱码问题,GET的又如何解决呢?(1)解决post申请乱码问题:在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8; <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)get申请中文参数呈现乱码解决办法有两个: ①批改tomcat配置文件增加编码与工程编码统一,如下: <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>②另外一种办法对参数进行从新编码: String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")ISO8859-1是tomcat默认编码,须要将tomcat编码后的内容按utf-8编码。 ...

November 23, 2022 · 1 min · jiezi

关于spring-mvc:如何使SpringMVC的表单和get请求参数支持json转换

该文章为原创(转载请注明出处):如何使SpringMVC的表单和get申请参数反对json转换? - 简书 (jianshu.com)实在业务场景前端申请须要表单传递json字符串或者get申请参数携带了json字符串的数据后端只能在格局上做斗争?例如: 前端表单userJson:{"name":"xxx", "phone":"123"}前端Get申请/user/test?userJson=%7B%22name%22%3A%22xxx%22%2C%20%22phone%22%3A%22123%22%7D 后端接管表单1@GetMapping("test.do")public RestResponse<Void> test(@ModelAttribute String userJson) { body.setUser(JSON.parseObject(userJson, User.class)); // service.handleUser(body);}@Datastatic class User { private String phone; private String name;}后端接管表单2@GetMapping("test.do")public RestResponse<Void> test(@ModelAttribute TestBody body) { body.setUser(JSON.parseObject(body.getUserJson(), User.class)); // service.handleUser(body);} @Datastatic class TestBody { private String userJson;}static class User { private String phone; private String name;}后端接管Get申请@GetMapping("test.do")public RestResponse<Void> test(@RequestParam String userJson) { body.setUser(JSON.parseObject(userJson, User.class)); // service.handleUser(body);}@Datastatic class User { private String phone; private String name;}反对json的解决方案利用springmvc提供的@ControllerAdvice切面,在WebDataBinder中退出应用json反序列化的形式来进行string与各种类型的转换 package com.nuonuo.accounting.guiding.support.spring;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;import com.alibaba.fastjson.util.TypeUtils;import org.springframework.core.convert.TypeDescriptor;import org.springframework.core.convert.converter.GenericConverter;import org.springframework.core.convert.support.GenericConversionService;import org.springframework.web.bind.WebDataBinder;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.InitBinder;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;import java.util.Set;import static java.util.Collections.singleton;/** * Fastjson来主动绑定参数 * 反对表单、get申请参数 * * @author uhfun * @see RequestMappingHandlerAdapter#initControllerAdviceCache() * 寻找@ControllerAdvice切面下@InitBinder注解的办法 * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#INIT_BINDER_METHODS * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDataBinderFactory(org.springframework.web.method.HandlerMethod) * 依据切面构建InitBinderMethod办法 * @see org.springframework.web.method.annotation.InitBinderDataBinderFactory#initBinder * 初始化binder时反射调用 * @see ModelAttribute */@ControllerAdvicepublic class StringToAnyObjectSupport { private static volatile boolean INITIALIZED = false; @InitBinder public void initStringToAnyObjectConverter(WebDataBinder dataBinder) { GenericConversionService conversionService; if (dataBinder.getConversionService() instanceof GenericConversionService) { if (!INITIALIZED) { conversionService = (GenericConversionService) dataBinder.getConversionService(); conversionService.addConverter(new StringToAnyObjectConverter()); INITIALIZED = true; } } else { throw new IllegalStateException("dataBinder的ConversionService不是GenericConversionService类型实例"); } } static class StringToAnyObjectConverter implements GenericConverter { @Override public Set<ConvertiblePair> getConvertibleTypes() { return singleton(new ConvertiblePair(String.class, Object.class)); } @Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Class<?> type = targetType.getType(); if (TypeUtils.getClassFromMapping(type.getName()) != null) { return TypeUtils.cast(source, type, ParserConfig.getGlobalInstance()); } else { return JSON.parseObject((String) source, type); } } }}如何应用?后端接管表单1@GetMapping("test.do")public RestResponse<Void> test(@ModelAttribute("userJson") User user) {} static class User { private String phone; private String name;}后端接管表单2@GetMapping("test.do")public RestResponse<Void> test(@ModelAttribute TestBody body) { User user = body.getUserJson(); // service.handleUser(body);} @Datastatic class TestBody { private User userJson;}static class User { private String phone; private String name;}后端接管Get申请@GetMapping("test.do")public RestResponse<Void> test(@RequestParam User userJson) { }@Datastatic class User { private String phone; private String name;}该文章为原创(转载请注明出处):如何使SpringMVC的表单和get申请参数反对json转换? - 简书 (jianshu.com)

October 22, 2022 · 2 min · jiezi

关于spring-mvc:SpringMVC学习记录

回顾MVC什么是MVCMVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示拆散的办法来组织代码。MVC次要作用是升高了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差别。Model(模型):数据模型,提供要展现的数据,因而蕴含数据和行为,能够认为是畛域模型或JavaBean组件(蕴含数据和行为),不过当初个别都拆散开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查问和模型数据的状态更新等性能,包含数据和业务。 View(视图):负责进行模型的展现,个别就是咱们见到的用户界面,客户想看到的货色。 Controller(控制器):接管用户申请,委托给模型进行解决(状态扭转),处理完毕后把返回的模型数据返回给视图,由视图负责展现。也就是说控制器做了个调度员的工作。 最典型的MVC就是JSP + servlet + javabean的模式。 Model1时代在web晚期的开发中,通常采纳的都是Model1。Model1中,次要分为两层,视图层和模型层。 Model1长处:架构简略,比拟适宜小型我的项目开发; Model1毛病:JSP职责不繁多,职责过重,不便于保护; Model2时代Model2把一个我的项目分成三局部,包含视图、管制、模型。 用户发申请Servlet接管申请数据,并调用对应的业务逻辑办法业务处理完毕,返回更新后的数据给servletservlet转向到JSP,由JSP来渲染页面响应给前端更新后的页面职责剖析Controller:控制器获得表单数据调用业务逻辑转向指定的页面Model:模型业务逻辑保留数据的状态View:视图就一个 显示页面Model2这样不仅进步的代码的复用率与我的项目的扩展性,且大大降低了我的项目的保护老本。Model 1模式的实现比较简单,实用于疾速开发小规模我的项目,Model1中JSP页面身兼View和Controller两种角色,将管制逻辑和体现逻辑混淆在一起,从而导致代码的重用性非常低,减少了利用的扩展性和保护的难度。Model2打消了Model1的毛病。MVC框架要做哪些事件将url映射到java类或java类的办法 .封装用户提交的数据 .解决申请--调用相干的业务解决--封装响应数据 .将响应的数据进行渲染 . jsp / html 等表示层数据 .常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等....回顾Servlet新建一个Maven工程springMVC当做父我的项目,而后新建一个maven子项目springMVC01-servlet,勾选模版maven-archetype-webapp编写pom.xml配置文件 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>xyz.rtx3090</groupId> <artifactId>SpringMVC-Review01</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> </project>替换SpringMVC-Review/SpringMVC-Review01/src/main/webapp/WEB-INF/web.xml为如下内容 ...

September 24, 2022 · 5 min · jiezi

关于spring-mvc:地摊秘笈之Spring-MVC源码二解密请求流程

概述Spring MVC的流程次要是从Servlet的service办法作为入口,以时序图为例,将一些要害的办法表明大抵理解流程所做的解决。 申请先进入DispatcherServlet的父类FrameworkServlet的service办法,进行PATCH办法的解决,其余办法调用FrameworkServlet]的父类HttpServlet的service办法,进行不同GET或POST等办法的不同解决。之后调用FrameworkServlet的processRequest办法,进行公布一些事件和调用DispatcherServlet的doService办法。而doService办法次要往request外面set一些属性,最次要还是在doDispatch进行散发申请。调用DispatcherServlet的doDispatch办法进行散发申请。调用DispatcherServlet的getHandler办法。次要进行遍历全副映射器处理器,通过映射器处理器找到处理器(Controller)和拦截器(HandlerInterceptor)。调用DispatcherServlet的getHandlerAdapter办法.次要进行遍历处理器适配器,失去能够反对进行适配的适配器。调用HandlerExecutionChain的拦截器前置办法applyPreHandle。应用适配器HandlerAdapter进行调用Controller的办法。次要进行应用适配器进行参数的映射,同时执行处理器(Controller),返回ModelAndView (数据Model和逻辑视图)。调用DispatcherServlet的applyDefaultViewName办法,对于没有逻辑视图给予默认视图。调用HandlerExecutionChain的拦截器后置办法applyPostHandle调用DispatcherServlet的processDispatchResult办法,进行解决散发的后果,外面也会进行异样的解决。调用DispatcherServlet的render办法,遍历视图解析器解决视图的逻辑名称,返回视图(View),而后应用视图(View)进行视图的渲染,并且将响应实体写进Response调用DispatcherServlet的triggerAfterCompletion办法,进行调用拦截器HandlerInterceptor的afterCompletion办法。

September 14, 2022 · 1 min · jiezi

关于spring-mvc:DispatcherServlet

概述Servlet WebApplicationContext容器的初始化基于咱们配置的DispatcherServlet,DispatcherServlet是Servlet 的实现,当Servlet进行初始化调用DispatcherServlet的父类HttpServletBean的init办法进行Servlet的初始化。复写Servlet的init办法的关键步骤如下: 将web.xml外面的配置进行赋值能够通过4种不同的形式初始化Servlet WebApplicationContext容器,进行配置和刷新初始化HandlerMapping,HandlerAdapter等组件DispatcherServlet类的UML 咱们看要害的几个实现之间的关系和性能 HttpServletBean : 将ServletConfig外面的配置赋值到ServletFrameworkServlet : 初始化和配置刷新Servlet WebApplicationContext容器DispatcherServlet :初始化 Spring MVC的各个组件,以及解决申请整体流程Servlet WebApplicationContext容器的初始化产生在,DispatcherServlet调用HttpServletBean的init办法,进行Servlet的初始化。次要将ServletConfig外面的配置赋值到Servlet。之后调用FrameworkServlet的initServletBean办法进行初始化Servlet WebApplicationContext,并配置和刷新上下文最初调用DispatcherServlet的onRefresh办法,进行组件的初始化分步解释调用HttpServletBean的init办法,将 ServletConfig 外面的InitParameter赋值到以后Servlet对象中 将ServletConfig外面的InitParameter配置转为PropertyValues,同时校验必须配置的配置项将PropertyValues外面的配置赋值到Servlet//org.springframework.web.servlet.HttpServletBean public final void init() throws ServletException { // Set bean properties from init parameters. // 将ServletConfig外面的配置转为PropertyValues,同时校验必须配置的配置项 PropertyValues pvs \= new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw \= PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader \= new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); // 将ServletConfig外面的配置赋值到Servlet bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // Let subclasses do whatever initialization they like. //FrameworkServlet进行了重载 initServletBean(); }将ServletConfig外面的InitParameter配置转为PropertyValues,同时校验必须配置的配置项 ...

September 14, 2022 · 5 min · jiezi

关于spring-mvc:Root-WebApplicationContext容器初始化和关闭

Root WebApplicationContext容器初始化和敞开概述Root WebApplicationContext的初始化是基于咱们配置的ContextLoaderListener,通过ContextLoaderListener实现了ServletContextListener监听Web容器启动触发contextInitialized办法,而后调用ContextLoader的initWebApplicationContext进行初始化。initWebApplicationContext关键步骤如下: 获取Root WebApplicationContext的Class类型,通过反射进行初始化配置和刷新Root WebApplicationContext将Root WebApplicationContext存储在ServletContext外面,用于上面的Servlet WebApplicationContext的父上下文。ContextLoaderListener类的UML ContextLoader :该类次要的性能通过调用initWebApplicationContext办法用来初始化Root WebApplicationContextServletContextListener :改接口是Servlet裸露进去的用于监听容器启动之后执行办法的监听器ContextLoaderListener:该类次要是ContextLoader和ServletContextListener的集成。所以从总体上看该类没有很多理论的性能,然而这样设计更加合乎繁多职责准则,逻辑更加的清晰,初始化和监听容器初始化进行离开。整体流程在web.xml配置的ContextLoaderListener实现了ServletContextListener接口,监听容器启动触发事件ServletContextEvent,触发ServletContextListener的contextInitialized办法调用ContextLoader的initWebApplicationContext进行初始化initWebApplicationContext办法次要蕴含以下两局部进行Root WebApplicationContext容器的初始化 调用ContextLoader的createWebApplicationContext办法,应用配置或者默认全类名应用反射进行创立Root WebApplicationContext上下文调用ContextLoader的configureAndRefreshWebApplicationContext进行配置Root WebApplicationContext上下文,并进行启动容器(也就是ConfigurableApplicationContext的refresh办法)将Root WebApplicationContext存储在ServletContext用于Servlet WebApplicationContext父上下文分步解释容器启动,ContextLoaderListener监听ServletContextEvent事件,调用ServletContextListener的contextInitialized办法进行初始化 //org.springframework.web.context.ContextLoaderListener @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } 调用ContextLoader的initWebApplicationContext进一步初始化 首先进行容器的初始化而后进行容器的配置和刷新最初将容器存在ServletContext//org.springframework.web.context.ContextLoader public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT\_WEB\_APPLICATION\_CONTEXT\_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader\* definitions in your web.xml!"); } servletContext.log("Initializing Spring root WebApplicationContext"); Log logger \= LogFactory.getLog(ContextLoader.class); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime \= System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context \== null) { //这里有两种状况 //1. 依据servletContext获取配置文件的contextClass获取全限定名应用个反射进行初始化 //2. 依据defaultStrategies配置文件默认的WebApplicationContext获取全限定名进行初始化 this.context \= createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac \= (ConfigurableWebApplicationContext) this.context; // 如果没有进行配置和激活,进行配置和激活 if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() \== null) { // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent \= loadParentContext(servletContext); cwac.setParent(parent); } //配置和激活上下文 configureAndRefreshWebApplicationContext(cwac, servletContext); } } // 将RootWebApplicationContext存储在servletContext中   servletContext.setAttribute(WebApplicationContext.ROOT\_WEB\_APPLICATION\_CONTEXT\_ATTRIBUTE, this.context); ClassLoader ccl \= Thread.currentThread().getContextClassLoader(); if (ccl \== ContextLoader.class.getClassLoader()) { currentContext \= this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isInfoEnabled()) { long elapsedTime \= System.currentTimeMillis() \- startTime; logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException | Error ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT\_WEB\_APPLICATION\_CONTEXT\_ATTRIBUTE, ex); throw ex; } }ContextLoader的createWebApplicationContext办法,进行初始化WebApplicationContext ...

September 14, 2022 · 3 min · jiezi

关于spring-mvc:从零搭建-Spring-MVC-项目-Validation

疾速开始1. 引入 Validation 依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId></dependency>2. 编写校验代码@Data 为 lombok 的注解,在此不做具体阐明。@Datapublic class UserRequest { @NotBlank private String name; @Min(0) @Max(200) private Integer age;}3. 申明校验参数@RestControllerpublic class UserController { @PostMapping("/api/users") public UserRequest createUser(@RequestBody @Validated UserRequest userRequest) { return userRequest; }}4. 捕获全局异样这一步不是必须的,目标是为了能不便查看校验后果。@ControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleMethodArgumentNotValidException( MethodArgumentNotValidException exception) { List<String> errorMessages = exception.getFieldErrors() .stream() .map(fieldError -> String.format("%s %s", fieldError.getField(), fieldError.getDefaultMessage())) .sorted() .collect(Collectors.toList()); Map<String, Object> errorMessageMap = CollectionUtils.newLinkedHashMap(2); errorMessageMap.put("code", HttpStatus.BAD_REQUEST.value()); errorMessageMap.put("message", errorMessages); return ResponseEntity.badRequest().body(errorMessageMap); }}5. 查看校验成果应用 curl 拜访接口: ...

August 20, 2022 · 3 min · jiezi

关于spring-mvc:从零搭建-Spring-MVC-项目-HelloWorld

1. 继承 Spring Boot 我的项目<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.2</version> <relativePath/></parent>2. 引入 Spring MVC 依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>3. 编写 Controller 代码@RestControllerpublic class HelloWorldController { @GetMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { return String.format("Hello %s!", name); }}4. 编写启动类@SpringBootApplicationpublic class HelloWorldApplication { public static void main(String[] args) { SpringApplication.run(HelloWorldApplication.class, args); }}5. 运行启动类运行启动类,在浏览器中输出:http://localhost:8080/hello?name=小穆 ,即可看到如下成果:

August 20, 2022 · 1 min · jiezi

关于spring-mvc:React组件应用于Spring-MVC工程

背景公司前端工程技术栈好处于React+Mobx与Spring MVC(freemarker+jQuery)两种技术栈共存的阶段,两种技术栈页面存在一些雷同的业务性能点,如果别离开发和保护,就须要双倍的人力老本,因而,下文将尝试将React业务组件在webpack、babel等利器的帮忙下利用于Spring MVC我的项目。 利用一、简略封装组件挂载与卸载办法React业务组件就是FunctionComponent或者ClassComponent,须要利用react-dom中的render办法解决,转化成Fiber双向链表树,造成虚构DOM,最初转成理论的HTMLElement追加到页面上。因而,在Spring MVC中应用须要抛出挂载与卸载的办法: // 引入polyfill,前面会将为什么不必@babel/polyfillimport 'react-app-polyfill/ie9';import 'react-app-polyfill/stable';import React from 'react';import ReactDOM from 'react-dom';import { MediaPreview } from './src/MediaPreview';// 引入组件库全副款式,前面会做css tree shaking解决import '@casstime/bricks/dist/bricks.development.css';import './styles/index.scss';;(function () { window.MediaPreview = (props, container) => { return { // 卸载 close: function () { ReactDOM.unmountComponentAtNode(container); }, // 挂载 open: function (activeIndex) { ReactDOM.render(React.createElement(MediaPreview, { ...props, visible: true, activeIndex: activeIndex || 0 }), container); // 或者 // ReactDOM.render(<MediaPreview {...{ ...props, visible: true, activeIndex: activeIndex || 0 }} />, container); }, }; };})();二、babel转译成ES5语法标准,polyfill解决兼容性apibabel在转译的时候,会将源代码分成syntax和api两局部来解决 ...

August 5, 2022 · 5 min · jiezi

关于spring-mvc:Spring-MVC流程简单解析

Spring MVC是以后Java Web应用最支流的架构模式,明天具体介绍下MVC的转发流程:1.首先当一个用户申请打过去,DispatcherServlet首先收到,将用户申请门路和参数封装,交给HandlerMaping进行查找匹配,期间如果有拦截器,则须要先通过定义的拦截器,HandlerMaping解决实现将后果返回DispatcherServlet。2.DispatcherServlet将返回后果交给HandlerAdapter进行解决,HandlerAdapter将工作转交给Controller进行解决,解决后的ModelAndView数据给HandlerAdapter,HandlerAdapter再转交给DispatcherServlet。3.DispatcherServlet调用View Reslover进行视图渲染解析,将渲染后的数据交给视图核心,视图核心将后果传递DispatcherServlet。4.此时数据渲染完结,由DispatcherServlet将渲染后的数据传递给用户。

July 20, 2022 · 1 min · jiezi

关于spring-mvc:Spring-Boot-ObjectMapper-配置不生效问题

问题后盾接管 Json 参数时有以下要求: 指定工夫格局疏忽不辨认的字段疏忽不辨认的枚举个别是配置 ObjectMapper 即可失效 配置 ObjectMapper@Bean@Primarypublic ObjectMapper objectMapper() { return new ObjectMapper() .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL) .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));}如上配置没有失效 配置 Jackson2ObjectMapperBuilderCustomizer@Bean@Primarypublic Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> builder .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .featuresToEnable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL) .simpleDateFormat("yyyy-MM-dd HH:mm:ss");}也不失效 解决方案解决方案援用自 Jackson2ObjectMapperBuilderCustomizer不失效解决不失效的起因个别是 MappingJackson2HttpMessageConverter 对象在程序启动时创立了多个,咱们只有将多余的去掉,并从新增加 MappingJackson2HttpMessageConverter 的 bean 就能够了 问题本源根底包中配置了 MappingJackson2HttpMessageConverter,导致应用服务工程中配置的 ObjectMapper 有效 @Configurationpublic class WebMvcConfig implements WebMvcConfigurer { @Autowired private RequestApiInterceptor requestApiInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(requestApiInterceptor).addPathPatterns("/**"); } @Bean public RequestApiInterceptor restfulApiInterceptor() { return new RequestApiInterceptor(); } /** * 解决controller返回string类型数据谬误 */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(0, new MappingJackson2HttpMessageConverter()); }}要害代码在应用服务工程中按如下配置性能失效 ...

June 17, 2022 · 1 min · jiezi

关于spring-mvc:Spring-MVC-前端控制器-DispatcherServlet处理流程

Spring MVC 申请解决流程 用户发动申请,到 DispatcherServlet;而后到 HandlerMapping 返回处理器链(蕴含拦截器和具体解决的 Handler);调用处理器链的适配器 HandlerAdapter 来解决;执行具体的办法,比方 @RequestMapper润饰的逻辑解决办法;返回后果的视图解析器;最初进行视图解析和渲染返回后果给用户; DispatcherServletDispatcherServlet是前置控制器,配置在web.xml文件中的。拦挡匹配的申请,Servlet拦挡匹配规定要本人定义,把拦挡下来的申请,根据相应的规定散发到指标Controller来解决,是配置spring MVC的第一步。DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中拜访点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而能够取得Spring的所有益处。源码剖析org.springframework.web.servlet.DispatcherServlet#doDispatch 办法是次要解决申请的源码如下:protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { try { try { // 文件上传相干 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // DispatcherServlet收到申请调用处理器映射器HandlerMapping。 // 处理器映射器依据申请url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包含处理器对象和处理器拦截器)一并返回给DispatcherServlet。 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } 4.DispatcherServlet依据处理器Handler获取处理器适配器HandlerAdapter, HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. HTTP缓存相干 String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 返回false就不进行后续解决了 return; } // 执行HandlerAdapter解决一系列的操作,如:参数封装,数据格式转换,数据验证等操作 // 执行处理器Handler(Controller,也叫页面控制器)。 // Handler执行实现返回ModelAndView // HandlerAdapter将Handler执行后果ModelAndView返回到DispatcherServlet mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 如果没有视图,给你设置默认视图 json疏忽 applyDefaultViewName(processedRequest, mv); //后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // DispatcherServlet将ModelAndView传给ViewReslover视图解析器 // ViewReslover解析后返回具体View // DispatcherServlet对View进行渲染视图(行将模型数据model填充至视图中)。 // DispatcherServlet响应用户。 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err));}finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } }}} 复制代码在doDispatch方中曾经涵盖了DispatcherServlet的主要职责:1、文件上传解析,如果申请类型是multipart将通过MultipartResolver进行文件上传解析;2、通过HandlerMapping,将申请映射到处理器(返回一个HandlerExecutionChain,它包含一个处理器、多个HandlerInterceptor拦截器);3、通过HandlerAdapter反对多种类型的处理器(HandlerExecutionChain中的处理器);4、通过ViewResolver解析逻辑视图名到具体视图实现;5、本地化解析;6、渲染具体的视图等;7、如果执行过程中遇到异样将交给HandlerExceptionResolver来解析。DispatcherServlet初始化的上下文加载的Bean是只对SpringMVC无效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文只加载Web相干组件。DispatcherServlet初始化次要做了如下两件事件:1、初始化SpringMVC应用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);2、初始化DispatcherServlet应用的策略,如HandlerMapping、HandlerAdapter等。 ...

May 28, 2022 · 2 min · jiezi

关于spring-mvc:SpringMVC-的五大核心组件

什么是 SpringMVC SpringMVC 是一个 WEB 层、管制层框架,次要用来负责与客户端交互,业务逻辑的调用。 SpringMVC 是 Spring 家族的一大组件.Spring 整合 SpringMVC 能够做到无缝集成。 特点,简略易用性能佳。 Java 全套学习材料支付链接:http://www.atguigu.com/download.shtml 为什么有了 Servlet 还要学 SpringMVC 1:Servlet 的开发配置绝对麻烦,servlet 特地多的时候 web.xml 文件将会十分臃肿 2:每个 Servlet 都只能解决一个性能,如果须要多个性能就须要开发多个 Servlet,我的项目中存在大量 Servlet 显得臃肿。 3:获取申请参数 进行类型转换 封装数据到 bean 的 过程比拟繁琐。 4:其余开发中不不便的中央,例如,乱码问题,数据格式解决,表单校验 SpringMVC 的组件 1:前端控制器(DispatcherServlet) 实质上是一个 Servlet,相当于一个中转站,所有的拜访都会走到这个 Servlet 中,再依据配置进行直达到相应的 Handler 中进行解决,获取到数据和视图后,在应用相应视图做出响应。 2:处理器映射器(HandlerMapping) 实质上就是一段映射关系,将拜访门路和对应的 Handler 存储为映射关系,在须要时供前端控制器查阅。 3:处理器适配器(HandlerAdapter) 实质上是一个适配器,能够依据要求找到对应的 Handler 来运行。前端控制器通过处理器映射器找到对应的 Handler 信息之后,将申请响应和对应的 Handler 信息交由处理器适配器解决,处理器适配器找到真正 handler 执行后,将后果即 model 和 view 返回给前端控制器 4:视图解析器(ViewResolver) 实质上也是一种映射关系,能够将视图名称映射到真正的视图地址。前端控制器调用处理器适配实现后失去 model 和 view,将 view 信息传给视图解析器失去真正的 view。 ...

April 19, 2022 · 1 min · jiezi

关于spring-mvc:编写Spring-MVC控制器的14个技巧

通常,在Spring MVC中,咱们编写一个控制器类来解决来自客户端的申请。而后,控制器调用业务类来解决与业务相干的工作,而后将客户端重定向到逻辑视图名称,该名称由Spring的调度程序Servlet解析,以出现后果或输入。这样就实现了典型的申请-响应周期的往返。 应用@Controller构造型这是创立能够解决一个或多个申请的控制器类的最简略办法。仅通过用构造型正文一个类@Controller ,例如: import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class HomeController { @RequestMapping("/") public String visitHome() { return "home"; }}如你所见,visitHome()办法通过重定向到名为home的视图来解决来自应用程序上下文门路(/)的申请。 留神:@Controller原型只能在Spring的配置文件中启用注解驱动时应用: <annotation-driven /> 启用正文驱动时,Spring容器主动在以下语句指定的包下扫描类: <context:component-scan base-package="net.codejava.spring" />由@Controller 正文正文的类被配置为控制器。这是最可取的,因为它很简略:无需在配置文件中为控制器申明bean。 留神:通过应用@Controller 注解,您能够领有一个多动作控制器类,该类可能解决多个不同的申请。例如: @Controllerpublic class MultiActionController { @RequestMapping("/listUsers") public ModelAndView listUsers() { } @RequestMapping("/saveUser") public ModelAndView saveUser(User user) { } @RequestMapping("/deleteUser") public ModelAndView deleteUser(User user) { }}正如你能够在下面的控制器类看,有解决三种不同的申请3种解决办法 /listUsers,/saveUser,和/deleteUser别离。 实现控制器接口在Spring MVC中创立控制器的另一种(兴许是经典的)办法是让类实现 Controller 接口。例如: import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;public class MainController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("Welcome main"); return new ModelAndView("main"); }}实现类必须重写该 handleRequest() 办法,当匹配申请进入时,该办法将由Spring调度程序Servlet调用。此控制器解决的申请URL模式在Spring的上下文配置文件中定义如下: ...

January 4, 2022 · 3 min · jiezi

关于spring-mvc:PathVariable和RequestParam的区别

简言之,@PathVariable用于接管在url门路中的参数,@RequestParam用于接管申请中的参数。例如: @RequestMapping("/hello/{id}")public String getDetails(@PathVariable(value="id") String id,@RequestParam(value="param1", required=true) String param1,@RequestParam(value="param2", required=false) String param2) {...}@RequestParam 反对上面四种参数defaultValue 如果本次申请没有携带这个参数,或者参数为空,那么就会启用默认值name 绑定本次参数的名称,要跟URL下面的一样required 这个参数是不是必须的value 跟name一样的作用,是name属性的一个别名 而@PathVariable 比@RequestParam少一个defaultValue

December 20, 2021 · 1 min · jiezi

关于spring-mvc:springmvc01Spring-MVC基本概念

1.1 Spring MVC基本概念 DispatcherServlet 前端控制器,前端用户的request申请通过DispatcherServlet分发给各个控制器来生成业务数据Model,再通过DispatcherServlet传递给View实现最终的页面出现。能够说Spring MVC将数据业务逻辑和页面出现拆散是通过DispatcherServlet实现的。HandlerAdapter Handler是DispatvherServlet外部应用的一个类,是DispatcherServlet调用Controller的一个两头过渡对象,能够看做是controller的一种表现形式,在Spring MVC中,通过各种annotation来辨认Controller,然而Spring MVC中没有相似于接口的controller或者interface来找到controller,最终controller以handler模式呈现。HandlerAdapter是适配器模式,将各种不同类型的handler适配成DispatcherServlet能够应用的handler,DispatcherServlet就能够很轻松的调用controller。HandlerInterceptor拦截器,在被拦挡对象的前后增加操作,这个接口有三种办法,preHandle,postHandle,afterCpmpletion。HandlerMappingMapping就是DispatcherServlet和Controller之间映射关系的一品种,负责通知DispatcherServlet在一个申请到来之后由哪一个Controller来响应本次申请。在HandlerMapping工作结束之后,会给DispatcherServlet返回一个HandlerAdapter,其中包含的内容一方面是某一个Controller具体的实例,另一方面是Controller被包裹的HnadlerInterceptor,形成了一个执行的链条HandlerExecutionChain往下走。HandlerExecutionChainModelAndView无论是Model还是Map,最终在DispatcherServlet中都会转换成ModelAndView,所以能够把ModelAndView看作Model的具体表现。

December 7, 2021 · 1 min · jiezi

关于spring-mvc:Spring-MVC-SortDefault多字段排序

在SpringMVC中,咱们能够应用@SortDefault或@PageableDefault来疾速的实现Pageable的默认排序。 咱们能查问到的大多数是对某一个字段进行排序: @PageableDefault(sort = {"weight"}, direction = Sort.Direction.DESC) Pageable pageable@SortDefault(sort = {"weight"}, direction = Sort.Direction.ASC) Pageable pageable或者对某几个字段进行排序,但排序的规定是雷同的(比方均为升序): @SortDefault(sort = {"weight", "createTime"}, direction = Sort.Direction.ASC) Pageable pageable如果咱们想设置多个排序字段,且各个排序字段的排序形式还不统一,则能够应用如下代码: public Page<Notice> page(@SortDefault.SortDefaults({ @SortDefault(sort = {"weight"}, direction = Sort.Direction.ASC), @SortDefault(sort = {"createTime"}, direction = Sort.Direction.DESC)}) Pageable pageable) {此时,上述代码便起到了先按weight进行升序排列,而后再按createTime进行逆序排序。

December 3, 2021 · 1 min · jiezi

关于spring-mvc:DispatchServlet源码解析

doDispatch()protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 为以后申请匹配处理器(HandlerExecutionChain) mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 为以后申请匹配HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } ... processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } ... }HandlerExecutionChain.class处理器实质上蕴含了HandleMethod和HandlerInterceptor的执行链 ...

November 5, 2021 · 2 min · jiezi

关于spring-mvc:spring-mvc-关于对optional的处理和自定义处理

springmvc4.1+可能反对optional参数,但不反对对象内field的optional。 举个例子 //对于这种间接在办法上定义的optional的根本类型或者援用类型//比方参数里没有id,或者没有obj,那么spring mvc会设置一个空的Optional对象//咱们能够通过Optional对象进行空判断@GetMapping("/get")public void test1(Optional<String> id, Optional<Object> obj) { id.ifPresent(i->{ });} //然而对于援用类型里field的Optional的话,spring mvc不反对//定义一个对象,外面属性用Optional类型@Datapublic class TestVo { Optional<Integer> id; Optional<String> name; } //如果这时候参数传了id,那么testVo.getId().get()能够拿到值//然而如果没有传name,这时的testVo的name属性为null而不是Optional的empty类型@GetMapping("/get")public Object test(TestVo testVo) { System.err.println(testVo.getId().get()); System.err.println(testVo.getName().isPresent()); //报空指针异样 return testVo;}咱们来看看springmvc是怎么解决的? 对于办法参数,spring mvc是如何赋值的呢? mvc有个RequestMappingHandlerAdapter,名称能够看出申请映射解决适配,就是它匹配咱们拜访的url门路和controller的requestMapping门路的,其中蕴含了一个HandlerMethodReturnValueHandler,处理结果赋值,以及HandlerMethodArgumentResolver(咱们讲这个),解决办法参数解析,就是由它进行参数赋值的,它有很多实现类,比方PathVariableMapMethodArgumentResolver就是咱们在参数上定义一个 @PathVariable时进行赋值的实现,RequestParamMapMethodArgumentResolver就是咱们在参数上定义一个 @RequestParam时进行赋值的实现。 那么平时默认的没有注解的援用类型,是通过哪个解析器呢?通过断点可知是通过ServletModelAttributeMethodProcessor来实现的。外面有WebDataBinder(题外话,WebDataBinder里有个ConversionService,这是spring提供的一个转换接口,底层应用BeanWrapper进行bean的操作),理论实现类是ExtendedServletRequestDataBinder(该类就是进行数据绑定的),bind办法里就是获取request的参数列表,因为咱们只传了id,没有传name,所以这里返回的MutablePropertyValues时外面就只有id(问题就出在这里),并设置id的值。 对于援用类型会应用到PropertyDescriptor(一系列的,属于java bean的标准)类设置列属性的值,TypeDescriptor记录属性类型,而后会依据属性名和参数类型获取PropertyEditor(PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName)),如果editor为空的话,就会优先应用后面提到的ConversionService(ConversionService conversionService = this.propertyEditorRegistry.getConversionService())实现参数类型转换。断点能够看到对于id字段应用的是ObjectToOptionalConverter类型,其实对于web参数申请类型,源参数类型都为string类型,也就是(TypeDescriptor的类型为string)。 发现如果对象外面还有个援用类型的属性字段且是Optional类型,则springmvc会抛异样Auto-growing not allowed with private constructor: private java.util.Optional(),这是因为,在springmvc进行赋值时,首先会调用无参结构初始对象,这时候因为java的泛型擦除,只能获取到Optional类型,而不能获取到具体的类型,Optional的结构是公有的就报错了。。所以springmvc是不反对对象嵌套应用Optional的。 那咱们须要对象里的根本类型字段设置Optional怎么弄呢? 原本想着在执行完springmvc的赋值前或者赋值后,设置对象里为null的Optional字段,后果看了一下,代码里写的很死,不能扩大webDataBinder,除非重写RequestMappingHandlerAdapter的createDataBinderFactory办法,返回一个自定义的webdatabinder,这个就比拟麻烦不贴代码了。。

November 3, 2021 · 1 min · jiezi

关于spring-mvc:springmvc关于404的异常处理原理

默认url的话其实springmvc会有很多MappingHandler进行适配(HandlerAdapter), 像咱们通常的RequestHandlerMappingHandler(通过Controller和 RequestMapping注解定义的门路), 这时候如果咱们没有一个requestMapping的url是拜访的url,mvc就会匹配到一个ResourceHttpRequestHandler(查找动态文件的处理器), 所以mvc这时候不会报错,然而又其实又没有对应的动态文件。 通过所有filter之后,会来到tomcat的StandardWrapperValue来解决前面的逻辑(实际上就是dispatchServlet解决,之后交由tomcat来解决), tomcat也没有找到,这时候tomcat就会设置一些谬误参数javax.servlet.error.status_code等,就会用到tomcat的errorPage,属性,这里springmvc会本人加上/error门路(对应着springmvc的BasicController), 而后tomcat会重定向到/error,就会到BasicController解决

November 3, 2021 · 1 min · jiezi

关于spring-mvc:SpringMVCInitBinder

前言由@InitBinder注解润饰的办法用于初始化WebDataBinder对象,可能实现:从request获取到handler办法中由@RequestParam注解或@PathVariable注解润饰的参数后,如果获取到的参数类型与handler办法上的参数类型不匹配,此时能够应用初始化好的WebDataBinder对获取到的参数进行类型解决。一个经典的例子就是handler办法上的参数类型为Date,而从request中获取到的参数类型是字符串,SpringMVC在默认状况下无奈实现字符串转Date,此时能够在由@InitBinder注解润饰的办法中为WebDataBinder对象注册CustomDateEditor,从而使得WebDataBinder能将从request中获取到的字符串再转换为Date对象。 通常,如果在@ControllerAdvice注解润饰的类中应用@InitBinder注解,此时@InitBinder注解润饰的办法所做的事件全局失效(前提是@ControllerAdvice注解没有设置basePackages字段);如果在@Controller注解润饰的类中应用@InitBinder注解,此时@InitBinder注解润饰的办法所做的事件仅对以后Controller失效。本篇文章将联合简略例子,对@InitBinder注解的应用,原理进行学习。 SpringBoot版本:2.4.1 注释一. @InitBinder注解应用阐明以前言中提到的字符串转Date为例,对@InitBinder的应用进行阐明。 @RestControllerpublic class LoginController { private static final String DATE_STRING = "20200620"; private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); private final Student student; public LoginController() { student = new Student(); student.setName("Lee"); student.setAge(20); student.setSex("male"); try { student.setDate(dateFormat.parse(DATE_STRING)); } catch (ParseException e) { System.out.println(e.getMessage()); } } @RequestMapping(value = "/api/v1/student/date", method = RequestMethod.GET) public ResponseEntity<Object> getStudentByDate(@RequestParam(name = "date") Date date) { if (student.getDate().equals(date)) { return new ResponseEntity<>(student, HttpStatus.OK); } else { return new ResponseEntity<>(String.format("get student failed by date: %s", date.toString()), HttpStatus.BAD_REQUEST); } }}@Datapublic class Student { private String name; private int age; private String sex; private Date date;}下面写好了一个简略的Controller,其中有一个Student成员变量,用于客户端获取,getStudentByDate()接口实现从申请中获取日期并与Controller中的Student对象的日期进行比照,如果统一,则向客户端返回Student对象。 ...

June 10, 2021 · 4 min · jiezi

关于spring-mvc:Error-creating-bean-with-name-userDao

问题形容 “Error creating bean with name 'userDao': Unsatisfied dependency expressed through field 'jdbcTemplate'” 形似: Error creating bean with name “xxx”: unsatisfied dependency expressed throuh field “xxxx” ⚠️ 谬误状态下的 userDao 和 jdbcTemplate下是有红线报错的! 谬误剖析上述表明: 没有创立 userDao的 bean,不满足 依赖字段“jbdcTemplate” 没有设置 注解扫描器,则 扫描包时,无奈注入注解到ICO容器 次要起因是 存在两个 spring配置文件,此时须要应用的 是 另一个,而另一个没有写扫描器和其余bean配置 <!-- 创立dataSource数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"/> <!-- 创立spring对jdbc反对的工具类 jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean>⚠️ UserDao是jdbcTemplate实现的,如果没有写上述代码,就没有dataSource和 jdbcTemplate,所以 userDao就没有 ♂️: 这是应用spring来实现jdbc的配置,注入的形式 而不是 应用java原生的连贯jdbc 问题解决增加相干 依赖 <!-- 创立dataSource数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"/> <!-- 创立spring对jdbc反对的工具类 jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> ...

June 5, 2021 · 1 min · jiezi

关于spring-mvc:简述一下SpringMVC的执行流程多看几遍对你没有坏处

MVC简介MVC是一种软件设计规范,模型(Model)、视图(View)、控制器(Controller)的缩写.MVC是一种常见的架构模式,其目标是为理解耦!Model(模型):数据模型提供页面要展现的数据,也叫业务逻辑层。模型层是一个宽泛的概述,模型层包含Service层、Dao层。View(视图):负责进行数据模型 + 视图框架的展现,也就是咱们看到的网页!Controller(控制器):接管用户申请,委托给模型进行解决,处理完毕后把返回的模型数据返回给视图,由视图负责展现。在MVC架构提出之前,Web页面的开发是只有模型、视图两层;也就是说没有Controller管制层,上面先来看看为什么MVC会胜利取代传统的两层架构在这里集体整顿了一些材料,有须要的敌人能够间接点击支付。 Java基础知识大全 22本Java架构师外围书籍 从0到1Java学习路线和材料 1000+道2021年最新面试题 长处:架构简略,容易实现。 毛病:视图层的职责不繁多;不仅须要对数据进行封装,还须要编写逻辑代码调用模型层也就是说这里的视图层充当了视图 + 管制两个职责;视图层间接与模型层打交道页面及其的凌乱、不利于保护 MVC架构提出是为了将视图与模型层离开,二者不间接打交道;而是通过管制层来从当二者交互的桥梁; 视图层只须要专一于数据封装与展现 模型层专一于业务逻辑 管制层负责解决用户递交的申请,并且协调视图与模型层 SpringMVC执行流程SpringMVC框架的外围围绕着DispatcherServlet前端控制器进行开展,它用于协调所有的Servlet对用户的申请进行解析、查找对应的Servlet进行解决、最初给出响应!能够将DispatcherServlet性能相似于CPU处理器、人类的大脑… 用户通过视图页面或者是url地址门路发动申请,前端管制DispatcherServlet接管用户的申请开始运作!DispatcherServlet调用HandlerMapping找到最终用于执行的HandlerHandlerExecution中包含具体的执行器Handler、HandlerInterceptor处理器拦截器。将其返回交给前端控制器DispatcherServlet。将获取到的HandlerExecution对象匹配对应的处理器适配器HandlerAdapter,将其进行解析。处理器适配器HandlerAdapter最终胜利匹配到程序员写的Controller层的Servlet类。Controller层职责明显,调用模型层进行数据库的拜访,并且获取到最初须要响应给用户的数据、视图。Controller层中将数据、视图封装在ModelAndView对象中,而后将其返回给处理器适配器HandlerAdapter。处理器适配器HandlerAdapter接管到Controller返回后果进行解决,而后移交给前端控制器DispatcherServlet。前端控制器DispatcherServlet调用视图解析器ViewResolver;ViewResolver解析ModelAndView中的数据、解析响应的视图名、找到对应的视图、最初将数据封装到视图中!视图解析器ViewResolver将视图名字返回给前端控制器DispatcherServlet,最初前端控制器DispatcherServlet调用响应的视图展现给用户!第一个SpringMVC程序JSP页面<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Title</title></head><body> <h1>${message}</h1></body></html>编写对应的Servlet(Controller)public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { // 1. 创立模型-视图 ModelAndView mv = new ModelAndView(); //调用业务层 // 2. 封装数据对象 mv.addObject("message","Hello, SpringMVC!"); // 3. 封装要跳转的视图,放在ModelAndView中 mv.setViewName("hellomvc"); return mv; }}配置SpringMVC外围文件外围配置文件中,配置映射器、适配器、解析器;最初将申请的门路以及对应的Servlet类交给IOC容器托管。 <?xml version="1.0" encoding="UTF8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 1. 配置处理器映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 2. 配置处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 3. 配置视图解析器 --> <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/page/"/> <!-- 后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 4. 将servlet交给IOC容器治理 --> <bean id="/hellomvc" class="com.controller.HelloController"/></beans>配置映射门路解决因为所有的Sevlet不在走各自的映射门路,而是对立由前端控制器DispatcherServlet调度,所以只须要在我的项目的web.xml中配置DispatcherServlet即可。而后将SpringMVC外围配置文件交给前端控制器DispatcherServlet主持! ...

May 17, 2021 · 1 min · jiezi

关于spring-mvc:SpringMVC基础之三SpringMVC的使用

1、SpringMVC的返回JSON数据 到目前为止咱们编写的所有Controller的办法的返回值都是String类型,然而大家应该都晓得,咱们有时候数据传递特地是在ajax中,咱们返回的数据常常须要应用json,那么如何来保障返回的数据的是json格局呢?应用@ResponseBody注解 pom.xml <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mashibing</groupId> <artifactId>springmv_ajax</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.3.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.3</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.3</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.10.3</version> </dependency> </dependencies></project>springmvc.xml ...

April 29, 2021 · 10 min · jiezi

关于spring-mvc:SpringMVC基础之三SpringMVC的使用

1、SpringMVC的返回JSON数据 到目前为止咱们编写的所有Controller的办法的返回值都是String类型,然而大家应该都晓得,咱们有时候数据传递特地是在ajax中,咱们返回的数据常常须要应用json,那么如何来保障返回的数据的是json格局呢?应用@ResponseBody注解 pom.xml <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mashibing</groupId> <artifactId>springmv_ajax</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.3.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.3</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.3</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.10.3</version> </dependency> </dependencies></project>springmvc.xml ...

April 26, 2021 · 10 min · jiezi

关于spring-mvc:HTTP-Status-500-–-Servletinit-for-servlet-springmvc-报错

近几天在做毕设的时候常常会呈现以下谬误HTTP Status 500 – Internal Server Error -Servlet.init() for servlet [springmvc] threw exception前一天关机前还能够失常运行,第二天重新启动时就报错。起初尝试clean了一下竟然就运行胜利了,然而还是不晓得是什么起因导致500

April 20, 2021 · 1 min · jiezi

关于spring-mvc:SpringMVC异常处理

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

April 16, 2021 · 1 min · jiezi

关于spring-mvc:传统JavaWeb的文件上传和SpringMVC提供额的文件上传

传统JavaWeb的文件上传1.前提 1.1form 表单的 enctype 取值必须是:multipart/form-data(用分隔符将表单分为几个局部,其中有表单元素的名称,也有你抉择的文件) (默认值是:application/x-www-form-urlencoded,它设置了将表单数据以键值对的模式上传) enctype:是表单申请注释的类型1.2 method 属性取值必须是 Post1.3 提供一个文件抉择域<input type=”file” />2.文件上传原理当 form 表单的 enctype 取值不是默认值后,request.getParameter()将生效。 enctype=”application/x-www-form-urlencoded”时,form 表单的注释内容是:key=value&key=value&key=value当 form 表单的 enctype 取值为 Mutilpart/form-data 时,申请注释内容就变成:每一部分都是 MIME 类型形容的注释-----------------------------7de1a433602ac 分界符Content-Disposition: form-data; name="userName" 协定头aaa 协定的注释-----------------------------7de1a433602acContent-Disposition: form-data; name="file"; filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"Content-Type: text/plain 协定的类型(MIME 类型)bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-----------------------------7de1a433602ac-- 这时须要先解析表单传输的数据体,找到表单上传的文件的局部,能力进行上传。借助jar包能够不便解析 3.借助第三方组件实现文件上传应用 Commons-fileupload 组件实现文件上传,须要导入该组件相应的撑持 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时须要 commons-io 包的反对导入依赖 <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>SpringMVC的文件上传 与传统文件上传的区别在于,SpringMVC框架可能代替咱们去解析request,拿到须要上传的文件。为应用该性能只须要引入SpringMVC曾经创立好的一个用于解析request的类:CommonsMultipartResolver1.编写用于上传文件的jsp页面 <h3>SpringMVC形式上传</h3> <form name="upload" action="work/upload2" method="post" enctype="multipart/form-data"> 抉择文件:<input type="file" name="upload"/><br> <input type="submit" value="上传"/> </form>2.在springmvc.xml中配置CommonsMultipartResolver: ...

April 16, 2021 · 1 min · jiezi

关于spring-mvc:SpringMVC框架搭建过程

一 创立maven工程,选中webapp,批改项名 二 补全目录构造 三 导入依赖 1.批改版本号<properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target></properties>2.版本锁定<properties> <spring.version>5.0.2.RELEASE</spring.version></properties>3.导入依赖<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency></dependencies>四 创立ContextConfiguration.xml 五 配置web.xml <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ContextConfiguration.xml</param-value> </init-param></servlet><servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern></servlet-mapping>六 创立Collector类七 配置ContextConfiguration.xml

April 9, 2021 · 1 min · jiezi

关于spring-mvc:Spring微服务项目实现优雅停机平滑退出

Spring微服务项目实现优雅停机(平滑退出)为什么要优雅停机(平滑退出) 不论是生产环境还是测试环境,在公布新代码的时候,不可避免的进行我的项目的重启 kill -9 `ps -ef|grep tomcat|grep -v grep|grep server_0001|awk '{print $2}' 以上是我司生产环境停机脚本,能够看出应用了 kill -9 命令把服务过程杀掉了,这个命令是十分暴力的,相似于间接按了这个服务的电源,显然这种形式对进行中的服务是很不友善的,当在停机时,正在进行RPC调用、执行批处理、缓存入库等操作,会造成不可挽回的数据损失,减少前期保护老本。 所以就须要优雅停机出场了,让服务在收到停机指令时,从容的回绝新申请的进入,并执行完当前任务,而后敞开服务。Java优雅停机(平滑退出)实现原理linux信号机制 简略来说,信号就是为 linux 提供的一种解决异步事件的办法,用来实现服务的软中断。 服务间能够通过 kill -数字 PID 的形式来传递信号 linux信号表kill -l 能够通过 kill -l 命令来查看信号列表: 取值名称解释默认动作1SIGHUP挂起 2SIGINT中断 3SIGQUIT退出 4SIGILL非法指令 5SIGTRAP断点或陷阱指令 6SIGABRTabort收回的信号 7SIGBUS非法内存拜访 8SIGFPE浮点异样 9SIGKILLkill信号不能被疏忽、解决和阻塞10SIGUSR1用户信号1 11SIGSEGV有效内存拜访 12SIGUSR2用户信号2 13SIGPIPE管道破损,没有读端的管道写数据 14SIGALRMalarm收回的信号 15SIGTERM终止信号 16SIGSTKFLT栈溢出 17SIGCHLD子过程退出默认疏忽18SIGCONT过程持续 19SIGSTOP过程进行不能被疏忽、解决和阻塞20SIGTSTP过程进行 21SIGTTIN过程进行,后盾过程从终端读数据时 22SIGTTOU过程进行,后盾过程想终端写数据时 23SIGURGI/O有紧急数据达到以后过程默认疏忽24SIGXCPU过程的CPU工夫片到期 25SIGXFSZ文件大小的超出下限 26SIGVTALRM虚构时钟超时 27SIGPROFprofile时钟超时 28SIGWINCH窗口大小扭转默认疏忽29SIGIOI/O相干 30SIGPWR关机默认疏忽31SIGSYS零碎调用异样 Java通过ShutdownHook钩子接管linux停机信号 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { logger.info("========收到敞开指令========"); logger.info("========登记Dubbo服务========"); shutdownDubbo(); logger.info("========登记ActiveMQ服务========"); shutdownActiveMQ(); logger.info("========登记Quartz服务========"); shutdownQuartzJobs(); } }, SHUTDOWN_HOOK));//public static final String SHUTDOWN_HOOK = "Manual-ShutdownHook-@@@" java提供了以上办法给程序注册钩子(run()办法外部为自定义的清理逻辑),来接管停机信息,并执行停机前的自定义代码。 ...

March 12, 2021 · 5 min · jiezi

关于spring-mvc:假装是小白之重学Spring-MVC二

在伪装是小白之重学Spring MVC(一)中曾经介绍了Spring MVC比拟罕用的知识点,然而还是有些脱漏,比方将申请放入Session,在配置文件中配置太烦了,咱们是否将配置文件挪动至配置类中,又比方SSM(Spring Spring MVC MyBatis)整合。本篇的次要内容就是介绍这些,将配置文件转换成配置类须要懂一些Spring的外围注解,比方@Import,这个注解在欢迎光临Spring时代(一) 上柱国IOC列传曾经介绍过了,不懂的能够再翻一下这篇文章。放入session中咱们如何将数据放入session中呢? 在原生Servlet时代,咱们从HttpServletRequest中获取HttpSession对象就好,像上面这样: 当然你在Spring MVC框架还能够接着用,Spring MVC又提供了@SessionAttributes注解用于将数据放入Session中,@SessionAttribute用于将session中的值,通过翻阅源码,咱们能够发现@SessionAttributes只能作用于类上,在翻阅源码的过程中发现了@SessionAttribute注解,原本认为和@SessionAttributes是一样的用途 ,起初翻源码才发现,这个是用来取出Session中的值放到办法参数中,只能作用办法参数上。又通过看源码的正文,咱们能够看到SessionAttributes的两个value和name是同义语,假如有申请域(申请域中的数据都是呈K、V对模式,我门当初谈的就是key)中有和value值雷同的数据,那么就会将该数据也会放到Session中。而Type属性则是,只有是申请域的数据是该类型的,就放入到Session中。咱们当初来测试一下@SessionAttributes: ControllerSessionAttributes(value = "password")public class SessionDemoController { @RequestMapping(value = "/session", method = RequestMethod.GET) public String testGet(@RequestParam(value = "name") String userName, @RequestParam(value = "password") String password ,Model model) { System.out.println("username:" + userName); System.out.println("password:" + password); model.addAttribute("password",password); return "success"; }}success.jsp: <%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Title</title></head><body><h1> success </h1><h1> username: ${sessionScope.userName}</h1><h1> password: ${sessionScope.password}</h1></body></html>url: http://localhost:8080/studySpringFrameWork_war_exploded/session?name=aa&&password=aaa 测试后果: SessionAttribute: RequestMapping(value = "/servlet", method = RequestMethod.GET) public String testGet(@RequestParam(value = "name") String userName, @SessionAttribute(value = "password")String password) { System.out.println("username:" + userName); System.out.println("password:" + password); return "success"; }url: http://localhost:8080/studySpringFrameWork_war_exploded/servlet?name=aaa测试后果: 能够看到url中没有password,password仍然打印进去有值,这个就是session中的值。 ...

March 10, 2021 · 3 min · jiezi

关于spring-mvc:假装是小白之重学Spring-MVC一

在编码一段时间之后,再从新看之前学过的框架,发现有新的认知,像Spring,我就重新学习了一把: 欢迎光临Spring时代-绪论欢迎光临Spring时代(一) 上柱国IOC列传代理模式-AOP绪论欢迎光临Spring时代(二) 上柱国AOP列传这次重学的是Spring MVC,以前学习Spring MVC的时候是在B站看的视频,的确不错,让我疾速入门了,然而我还是感觉不是很零碎,感觉知识点四分五裂,我心愿用我的形式将这些形式串联起来。在学习本篇之前,须要有Java EE和Spring Framework的根底,如果没有Java EE的根底,能够参看JavaWeb视频教程,如果没有Spring Framework的根底,请参看我下面的文章,如果感觉四篇有点多,能够先只看 欢迎光临Spring时代(一) 上柱国IOC列传,如果能够的话,还是倡议先看完下面四篇文章来看这四篇文章。 原生Servlet时代的问题简略的说Servlet是Java中的一个接口,位于javax.servlet下。咱们来看一下Servlet上的正文: A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients,usually across HTTP, the HyperText Transfer Protocol. Servlet是一个运行在Web 服务器中的一个小Java程序,Servlet接管和解决Web 客户端的申请,通常用于Http协定。咱们通常用的是它的实现类HttpServlet,而后重写doGet和doPost办法,像上面这样:WebServlet(name ="/servlet")public class ServletDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getParameterNames(); req.getParameter("username"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 解决post申请 super.doPost(req, resp); }}它有哪些痛点呢? 第一个就是取参数的问题,取参数只有这一种形式,参数一多就有点让人心烦了,不是那么的合乎面向对象的思维,程序员除了关怀业务逻辑的,还要关注如何获取参数,确实HttpServletRequest外面搁置的参数很多了,很全很全: 那getParameterNames去哪里了? HttpServletRequest 是一个接口,getParameterNames从ServletRequest继承而来。是否让程序员更加专一于业务逻辑一点呢,让取参数变的更简略一些,比方我想用学生类对象接管,又比方我须要的参数只有一个Long类型的id,接管参数的时候是否就间接让用Long id来接管呢。这是咱们提出的第一个问题,取参数是否变的简略一些。除了取参数,在Ajax技术曾经广泛利用的明天,是否让我响应前端的Ajax申请在简略一些呢? 在原生Servlet,咱们解决Ajax,咱们在响应中的设置编码,设置响应的类型,而后通过一些Java的JSON库将咱们的对象转成JSON模式,发送给前端,大抵上要这么做: ...

March 10, 2021 · 5 min · jiezi

关于spring-mvc:SpringMVC

1.MVC概述MVC(Model–view–controller)是软件工程中的一种软件架构模式,基于此模式把软件系统分为三个根本局部:模型(Model)、视图(View)和控制器(Controller)。目标是通过这样的设计使程序结构更加简洁、直观,升高问题的复杂度。其中各个组成部分的职责为: 视图(View) - UI设计人员进行图形界面设计,负责实现与用户交互。控制器(Controller)- 负责获取申请,解决申请,响应后果。模型(Model) - 实现业务逻辑,数据逻辑实现。咱们在软件设计时,通常要遵循肯定的设计准则。MVC架构模式的设计中,首先基于繁多职责准则(SRP-Single responsibility principle)让每个对象各司其职,各尽所能。而后再基于“高内聚,低耦合”的设计思维实现相干层对象之间的交互。这样能够更好进步程序的可维护性和可扩展性。 Spring MVC 是Spring 框架中基于MVC设计思维实现的一个用于解决Web申请的模块。其繁难架构剖析,如图所示: 外围组件剖析: DispatcherServlet :前端控制器, 解决申请的入口。HandlerMapping:映射器对象, 用于治理url与对应controller的映射关系。Interceptors:拦截器,实现申请响应的共性解决。Controller:后端控制器-handler, 负责解决申请的管制逻辑。ViewResolver:视图解析器,解析对应的视图关系(前缀+viewname+后缀)。2.SpringMVC的工作原理1、客户端收回一个http申请给web服务器,web服务器对http申请进行解析,如果匹配DispatcherServlet的申请映射门路(在web.xml中指定),web容器将申请转交给DispatcherServlet. 2、DipatcherServlet接管到这个申请之后将依据申请的信息(包含URL、Http办法、申请报文头和申请参数Cookie等)以及HandlerMapping的配置找到解决申请的处理器(Handler)。 3-4、DispatcherServlet依据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的解决进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。 5、Handler对数据处理实现当前将返回一个ModelAndView()对象给DispatcherServlet。 6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。 7、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出残缺的view并返回给客户端。

March 9, 2021 · 1 min · jiezi

关于spring-mvc:spring-MVC实践

应用spring mvc提供restful格调的接口,实现前后端拆散,后端只提供数据接口,而不做页面渲染。因而可对接口做对立解决: 申请参数校验响应数据格式全局异样解决通过以上对立解决,开发人员可专一于业务解决,把校验,异样响应的逻辑分离出来。 申请参数校验: 对于url中的参数 如果增加@RequestParam,但没有传递该参数,则抛出MissingServletRequestParameterException异样如果增加@Max等注解,同时不满足该条件,抛出ConstraintViolationException 或BindException异样对于request body申请体中的参数 Bean前增加@RequestBody,如果没有申请体,抛出HttpMessageNotReadableException异样在bean前增加@Validate注解,bean中属性增加@Max,@NotNull等注解,即对响应属性进行校验,如果不满足,抛出MethodArguementNotValidException@Validate内可增加group,表明须要校验的操作,@Max可增加groups,当groups蕴含group时,则进行校验。Bean中也可自定义注解,通过实现ConstraintValidator接口自定义校验逻辑。如果校验失败,会抛出MethodArgumentNotValidException异样,这些异样都被全局异样解决拦挡,返回异样信息。 响应数据格式: 建设对立响应类JsonResp<T>,泛型T为业务响应内容,可为String,List,java bean等。定义属性result表明响应是否胜利,响应码code,响应码信息msg。这里code及msg与全局异样解决的响应枚举类绝对应。定义ResponseBodyhandler实现ResponseBodyAdvice接口,当响应类型为json时,如果响应类型为JsonResp,间接响应给客户端;如果不是,则new JsonResp,将响应体set进去,响应给客户端。在controller的办法返回类型可任意定义String,List,java bean,在ResponseBodyhandler转化为对立JsonResp模式。如果是流文件,则间接返回不会转化为JsonResp模式。这样可将响应包装成对立的JsonResp数据格式,便于前端解决。全局异样解决 建设响应枚举类ResponseEnum,定义业务须要的响应码及响应码信息建设自定义异样类BaseException,继承运行时异样RuntimeException,初始化时设置ResponseEnum。建设异样捕获类GlobalExceptionAspect,类中增加@RestCOntrollerAdvice注解,应用@Exceptional捕获参数校验异样和自定义异样BaseException。最外层捕获Exception,捕获未定义的异样如果遇到业务报错,throw new BaseException(ResponseEnum.xxx),抛出自定义异样,该异样由GlobalExceptionAspect切面捕获,对立响应至客户端对立定义异样响应码,便于查看防止在业务代码里进行异样的响应,简化代码 这些对立解决的实质是应用fliter或者aop拦挡申请和响应参数进行通用逻辑解决,因而,可对申请进行敏感词过滤,参数加解密等解决,解耦业务逻辑。

March 3, 2021 · 1 min · jiezi

关于spring-mvc:SpringMVC

1 Spring与Web环境集成1.1 ApplicationContext利用上下文利用上下文的获取形式 形式一 通过Spring配置文件形式获取 new classpathXmlApplicationContext弊病:配置文件加载屡次 利用上下文对象创立屡次 因为每次从容器中获取Bean都要编写上述代码 创建对象形式二 从域中获取利用上下文ApplicationContext对象 通过 ServletContextListener监听Web利用的启动 在web利用启动时,就加载Spirng的配置容器,创立利用上下文对象ApplicationContext, 在将其存储到最大的域servletContext域中,这样就能够在任意地位从域中取得利用上下文ApplicationContext对象了1.2 Spring提供利用上下文的工具Spring 提供了一个监听器ContextLoaderListener就是对上述性能的封装,该监听器外部加载Spring配置文件,创立利用上下文对象,并存储草ServletContext域中,提供了一个客户端工具 WebApplicationContextUtils供使用者取得利用上下文对象 办法 1 在web.xml中配置ContextLoaderListener监听器(导入Spring-web坐标) `<dependency> < ` 2 应用WebApplicationContextUtils取得利用上下文对象ApplicationContext1.3 导入Spring集成web坐标1.4 配置ContextLoaderListener监听器1.5 通过工具取得利用上下文对象2 SpringMVC的简介2.1 SpringMVC概述2.2 SpringMVC疾速入门2.3 SpringMVC流程试图2.4 常识要点3 ingMVC的组件解析3.1 SpringMVC的执行流程3.2 SpringMVC组件解析3.3 SpringMVC正文解析3.4 SpringMVC的XML配置解析3.5 只是要点4 ringMVC的数据相应4.1 数据相应形式(了解)4.2 返回字符串模式(利用4.3 页面跳转-返回ModelAndView模式1 (利用)4.4 页面跳转-返回ModelAndView模式2 (利用)4.5 页面跳转-返回ModelAndView模式3 (利用)4.6 回写数据-间接滑稽字符串 (利用)4.7 回写数据-间接回写json格局字符串 (利用)4.8 回写数据-返回对象或汇合 (利用)4.9 回写数据对象或汇合2 (利用)4.10 常识要点小结 (了解,记忆)5 SpringMVC申请5.1 取得申请参数-申请参数类型(了解)5.2 取得申请参数-取得根本类型参数(利用)5.3 取得申请参数-取得POJO类型参数(利用)5.4 取得申请参数-取得数组类型参数(利用)5.5 取得申请参数-取得汇合类型参数1(利用)5.6 取得申请参数-取得汇合类型参数2(利用)5.7 取得申请参数-动态资源拜访的开启(利用)5.8 取得申请参数-配置全局乱码过滤器(利用)5.9 取得申请参数-参数绑定注解@RequestParam(利用)5.10 取得申请参数-Restful格调的参数的获取(利用)5.11 取得申请参数-自定义类型转换器(利用)5.12 取得申请参数-取得Servlet相干API(利用)5.13 取得申请参数-取得申请头信息(利用)5.14 文件上传-客户端表单实现(利用)5.15 文件上传-文件上传的原理(了解)5.16 文件上传-单文件上传的代码实现1(利用)5.17 文件上传-单文件上传的代码实现2(利用)5.18 文件上传-多文件上传的代码实现(利用)5.19 常识要点(了解,记忆)

February 9, 2021 · 1 min · jiezi

关于spring-mvc:6-SpringBoot工程中Spring-MVC模块的应用

一.背景剖析当我的项目做的越来越来大时,我的项目中业务就会变得越来越简单,如果咱们只应用一个对象去解决所有的业务,这个对象的复杂度就会更高并且难以保护,生存中和理论我的项目中对相似问题的解决计划往往"分而治之"的思维.来升高业务复杂度,进步其可维护性.那当初的问题的是如何分,依照什么规定去分,这就须要有肯定的设计,于是MVC设计思维诞生. 二.MVC是什么?MVC是一种软件架构设计思维,基于MVC架构将咱们的应用软件进行分层设计和实现,例如能够分为视图层(View),管制层(Controller),模型层(Model),通过这样的分层设计让咱们程序具备更好的灵活性和可可扩展性.因为这样能够将一个简单应用程序进行简化,实现各司其职,各尽所能.比拟适宜一个大型利用的开发。 1)是一种分层架构设计思维,也是一种套路工设计模式。2)是Model,View,Controller单词的缩写。Model(业务逻辑对象,业务层)View(显示逻辑对象,体现层)Controller(管制逻辑对象,管制层) 程序中的MVC? (Web利用)1.传统的web利用?企业中业务零碎->CRM,BOSS,ERP,EBanking,... 2.互联网利用?领取零碎,网约车,... 三.Spring 框架中Web模块中的MVC设计Spring MVC是MVC设计思维在Spring框架中的一种实现,基于这样的思维spring框架设计了一些相干对象,用于更好的基于MVC架构解决申请和响应,其繁难架构如图所示: 其外围组件有:1.DispathcherServlet(外围控制器,前端控制器,Controller)是客户端所有申请解决的入口,负责申请转发。 2.RequestMapping(申请映射)负责存储申请url到后端handler对象之间的映射。 3.Handler(申请处理器)用于解决DispatcherServlet对象转发过去的申请数据。 4.ModelAndView(业务数据和视图信息的对象)用于封装业务数据和视图信息的对象 5.ViewResolver(视图解析器,View)负责解决所有Handler对象响应后果中。 四.SpringBoot 工程中Web MVC 疾速入门实现筹备工作第一步:创立我的项目module,根本信息如图所示: 第二步:增加我的项目依赖(能够在module创立时,也能够创立后),代码如下:Spring Web 依赖(提供了spring mvc反对并且会嵌入一个tomcat) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>Thymeleaf 依赖(提供了以html作为页面模板进行解析和操作的相干对象) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>第三步:启动我的项目检测控制台启动状态,是否运行胜利static目录剖析及利用static 目录为springboot工程创立时增加了web依赖当前主动创立的目录,此目录中能够存储html、css、js、image,这些资源能够在启动服务器当前,间接在浏览器进行拜访。 例如: 第一步:在static目录下创立一个index.html页面,代码如下:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>The static directory index.html page</h1></body></html>第二步:启动服务器并间接进行拜访测试,如图所示 templates 目录剖析及利用templates 目录为springboot工程创立时增加了thymeleaf依赖当前主动创立的目录,此目录中要存储一些html模板,这个模板页面不能间接通过浏览器url进行拜访,须要基于后端控制器,在办法中定义页面响应,例如: 第一步:定义TemplateController及办法,代码如下:package com.cy.pj.health.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class TemplateController { @RequestMapping("doTemplate") public String doTemplateUI(){ return "default"; }}第二步:在templates目录中定义模板页面default.html,代码如下:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>The template directory default page</h1></body></html>其中,如果default.html要在放在templates子目录中,则还须要在配置文件中配置thymeleaf的前缀,例如: ...

December 29, 2020 · 1 min · jiezi

关于spring-mvc:深入解析SpringMVC核心原理从手写简易版MVC框架开始SmartMvc

简介SpringMVC能够说的上是以后最优良的MVC框架,采纳了涣散耦合可插拔组件构造,比其余MVC框架更具扩展性和灵活性;为了进步框架的扩展性和灵活性,设计了松耦合可插拔的组件。了解SpringMVC的原理,在面试或工作中都非常的重要。 SpringMVC的原理在网络上到处都能够找失去,然而写的都很概括、零散;对应浏览源码教训较少的小伙伴来说,本人去看源码被很多细节所烦扰妨碍,不可能很好的抽离出springMVC原理的主线。 本人想和小伙伴一起从手写简易版的SmartMVC框架登程,理出SpringMVC的主线并深刻了解SpringMVC的原理。框架代码开发加上文档编写大略破费工夫一个月 我的项目构造SmartMvc├── docs -- 开发文档├── smart-mvc -- 实现mvc性能的外围代码├── smartmvc-springboot-autoconfigure -- SmartMvc的自动化配置├── smartmvc-springboot-demo -- SmartMvc的demo我的项目├── smartmvc-springboot-starter -- SmartMvc的starter└── spring-mvc-demo -- SpringMVC的demoIDE、源码、依赖版本JDK的版本1.8整个开发过程中我应用的IDE都是IDEA,能够依据读者本人习惯抉择。当然我举荐是用IDEA开发SmartMVC咱们须要应用到Spring,我应用的版本5.2.9整个框架曾经开发实现,SmartMVC的源码地址: Github: https://github.com/silently9527/SmartMvc码云:https://gitee.com/silently9527/SmartMvc大家记得棘手给个star哦约定为了便于前期了解和应用SpringMVC,所以在SmartMVC中所有组件的名称都和SpringMVC的保持一致为了让SpringMVC的外围流程更加的清晰,缩小的烦扰,我拿出了本人18米的砍刀大胆的砍掉了SpringMVC中很多细节流程,达到去枝干立主脑,让咱们可能更加顺畅的了解申请的处理过程文档目录所有开发文档都在我的项目的docs目录下 01 SmartMVC总体架构布局02 RequestMappingHandlerMapping初始化过程03 拦截器HandlerInterceptor04 HandlerMapping获取对应的Handler05 参数解析器HandlerMethodArgumentResolver06 返回解析器HandlerMethodReturnValueHandler07 Handler执行器InvocableHandlerMethod08 实现RequestMappingHandlerAdapter09 视图InternalResourceView、RedirectView10 视图解析器ViewResolver11 DispatcherServlet实现doDispatch来实现申请逻辑12 全局异样处理器HandlerExceptionResolver13 外围配置类WebMvcConfigurationSupport14 SmartMvc与SpringBoot集成(一)15 SmartMvc与SpringBoot集成(二)16 SmartMvc我的项目实战SpringBoot我的项目中引入SmartMVC的步骤1. 新建一个SpringBoot我的项目,在pom.xml中退出SmartMVC的starter<dependency> <groupId>com.silently9527</groupId> <artifactId>smartmvc-springboot-starter</artifactId> <version>1.0.0-SNAPSHOT</version></dependency>2. 批改SpringBoot生成的启动类,指定SmartMVC的ApplicationContextClass@SpringBootApplicationpublic class SmartmvcSpringbootDemoApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(SmartmvcSpringbootDemoApplication.class); application.setApplicationContextClass(ServletWebServerApplicationContext.class); application.run(args); }}写到最初(点关注,不迷路)在开发文档中可能会存在谬误或不足之处,欢送大家指出。 创作不易,心愿敌人们能够点赞评论关注三连 原文地址,转载请注明出处:https://silently9527.cn/archives/88

December 28, 2020 · 1 min · jiezi

关于spring-mvc:上传文件异步处理注意事项

问题上传Excel进行解决 不必用户期待 解决完之后 会邮件告知处理结果所以是异步解决 public void readExcel(@RequestParam("file") MultipartFile file) { CompletableFuture.runAsync(() -> { try { service.readExcel(file); } catch (IOException e) { e.printStackTrace(); } });}理论应用的过程中 发现常常上传失败 报错如下 java.io.FileNotFoundException: /private/tmp/upload_2cc08ec8_c3eb_4633_8c0f_0cc20e34ff55_00000000.tmp (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:188) at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100) at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:297)起因申请返回后 会主动删除临时文件 导致理论读取Excel的时候 找不到文件 // org.apache.catalina.core.ApplicationPart#deletepublic void delete() throws IOException { fileItem.delete();}解决复制该临时文件 将复制后的文件传给异步程序处理 解决完之后删除该临时文件 String uuid = UUID.randomUUID().toString().replace('-', '_');String tmpFileName = String.format("/tmp/upload_%s.tmp", uuid);final File tmpFile = new File(tmpFileName);try { Files.copy(file.getInputStream(), tmpFile.toPath());} catch (IOException e) { e.printStackTrace();}CompletableFuture.runAsync(() -> { try { service.readExcel(tmpFile); } catch (IOException e) { e.printStackTrace(); }});参考文档https://stackoverflow.com/que... ...

December 19, 2020 · 1 min · jiezi

关于spring-mvc:你知道目前最流行的SpringMVC框架如何搭建吗

Spring MVC 是 Spring 家族中的一个 web 成员, 它是一种基于 Java 的实现了 Web MVC 设计思维的申请驱动类型的轻量级 Web 框架,即应用了 MVC 架构模式的思维,将 web 层进行职责解耦,基于申请驱动指的就是应用申请-响应模型,框架的目标就是帮忙咱们简化开发,Spring MVC 也是要简化咱们日常 Web 开发的。 Spring MVC 是服务到工作者思维的实现。前端控制器是 DispatcherServlet;利用控制器拆为处理器映射器(Handler Mapping)进行处理器治理和视图解析器(View Resolver)进行视图治理;反对本地化/国际化(Locale)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了弱小的约定大于配置(常规优先准则)的契约式编程反对。 SpringMVC 搭建的形式开发环境搭建新建 Maven webAppSpringmvc 环境 jar 包依赖配置 web.xml (前端控制器配置)servlet-context.xml 配置页面控制器的编写增加视图页面启动 jetty 服务器案例实操开发环境搭建Eclipse + jdk1.7 + maven + Jetty 新建 Maven webApp建设 springmvc01 工程并调整 web 环境。 Springmvc 环境 jar 包依赖<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven...d"> <modelVersion>4.0.0</modelVersion> <groupId>com.xxx</groupId> <artifactId>springmvc01</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springmvc01 Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- spring web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- web servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> </dependencies> <!-- jetty 插件 --> <build> <finalName>springmvc01</finalName> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <plugins> <!-- 编译环境插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.25</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <contextPath>/springmvc01</contextPath> </configuration> </plugin> </plugins> </build></project> ...

December 17, 2020 · 3 min · jiezi

关于spring-mvc:你知道什么是-Restful-风格吗SpringMVC-带我们实现它

Restful 格调的 API 是一种软件架构格调,设计格调而不是规范,只是提供了一组设计准则和约束条件。它次要用于客户端和服务器交互类的软件。基于这个格调设计的软件能够更简洁,更有档次,更易于实现缓存等机制。 在 Restful 格调中,用户申请的 url 应用同一个 url 而用申请形式:get,post,delete,put...等形式对申请的解决办法进行辨别,这样能够在前后台分离式的开发中使得前端开发人员不会对申请的资源地址产生混同和大量的查看办法名的麻烦,造成一个对立的接口。 SpringMVC Restful 格调 url 配置实现的形式SpringMVC 的 resturl 是通过 @RequestMapping 及 @PathVariable annotation 提供的,通过如 @RequestMapping(value="/blog /{id}",method=RequestMethod.DELETE) 即可解决 /blog/1 的 delete 申请。 GET(SELECT):从服务器查问,能够在服务器通过申请的参数辨别查问的 形式。POST(CREATE):在服务器端新建一个资源,调用 insert 操作。PUT(UPDATE):在服务器端更新资源,调用 update 操作。PATCH(UPDATE):在服务器端更新资源(客户端提供扭转的属性)。(目前 jdk7 未实现,tomcat7 不反对)。DELETE(DELETE):从服务器端删除资源,调用 delete 语句。案例实操Get 申请配置/***restful-->get 申请 执行查问操作 @param id@return*/@RequestMapping(value="queryAccountById02/{id}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)@ResponseBodypublic MessageModel queryAccountById(@PathVariable Integer id){ MessageModel messageModel=new MessageModel(); if(null==id){ messageModel.setCode(300); messageModel.setMsg("参数非法!"); return messageModel; } messageModel.setResult(accountService.queryById(id)); return messageModel; } Post 申请配置/** ...

December 17, 2020 · 1 min · jiezi

关于spring-mvc:你知道目前最流行的SpringMVC框架吗如何搭建呢

Spring MVC 是 Spring 家族中的一个 web 成员, 它是一种基于 Java 的实现了 Web MVC 设计思维的申请驱动类型的轻量级 Web 框架,即应用了 MVC 架构模式的思维,将 web 层进行职责解耦,基于申请驱动指的就是应用申请-响应模型,框架的目标就是帮忙咱们简化开发,Spring MVC 也是要简化咱们日常 Web 开发的。 Spring MVC 是服务到工作者思维的实现。前端控制器是 DispatcherServlet;利用控制器拆为处理器映射器(Handler Mapping)进行处理器治理和视图解析器(View Resolver)进行视图治理;反对本地化/国际化(Locale)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了弱小的约定大于配置(常规优先准则)的契约式编程反对。 SpringMVC 搭建的形式开发环境搭建新建 Maven webAppSpringmvc 环境 jar 包依赖配置 web.xml (前端控制器配置)servlet-context.xml 配置页面控制器的编写增加视图页面启动 jetty 服务器案例实操开发环境搭建Eclipse + jdk1.7 + maven + Jetty 新建 Maven webApp建设 springmvc01 工程并调整 web 环境。 Springmvc 环境 jar 包依赖<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xxx</groupId> <artifactId>springmvc01</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springmvc01 Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- spring web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- web servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> </dependencies> <!-- jetty 插件 --> <build> <finalName>springmvc01</finalName> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <plugins> <!-- 编译环境插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.25</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <contextPath>/springmvc01</contextPath> </configuration> </plugin> </plugins> </build></project> 配置 web.xml (前端控制器配置)<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <!-- 示意容器启动时 加载上下文配置 这里指定 spring 相干配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:*.xml</param-value> </context-param> <!-- 启用 spring 容器环境上下文监听 --> <listener> <listener class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 编码过滤 utf-8 --> <filter> <description>char encoding filter</description> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- servlet 申请散发器 --> <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:servlet-context.xml</param-value> </init-param> <!-- 示意启动容器时初始化该 Servlet --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <!-- 这是拦挡申请, /代表拦挡所有申请,拦挡所有.do 申请 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> 要想启动咱们的 springMvc 环境,目前对于 mvc 框架的配置还未进行。以上在 web.xml 中援用了 servlet-context.xml 文件。 ...

December 10, 2020 · 3 min · jiezi

关于spring-mvc:06SpringBoot工程下Spring-MVC技术的应用

Spring MVC 简介背景剖析在大型软件系统设计时,业务个别会绝对简单,如果所有业务实现的代码都纠缠在一起,会呈现逻辑不清晰、可读性差,保护艰难,改变一处就牵一发而动全身等问题。为了更好解决这个问题就有了咱们当初常说的分层架构设计。 MVC 是什么MVC是一种软件架构设计思维,基于MVC架构将咱们的应用软件进行分层设计和实现,例如能够分为视图层(View),管制层(Controller),模型层(Model),通过这样的分层设计让咱们程序具备更好的灵活性和可可扩展性.因为这样能够将一个简单应用程序进行简化,实现各司其职,各尽所能.比拟适宜一个大型利用的开发. Spring MVC 概述Spring MVC是MVC设计思维在Spring框架中的一种实现,基于这样的思维spring框架设计了一些相干对象,用于更好的基于MVC架构解决申请和响应,其繁难架构如图所示: 其中:1)DispatcherServlet是客户端所有申请解决的入口,负责申请转发。2)RequestMapping负责存储申请url到后端handler对象之间的映射。3)Handler 用于解决DispatcherServlet对象转发过去的申请数据。4)ViewResolver负责解决所有Handler对象响应后果中的view。 Spring MVC 疾速入门筹备工作第一步:创立我的项目module,根本信息如图所示: 第二步:增加我的项目依赖(能够在module创立时,也能够创立后),代码如下: Spring Web 依赖(提供了spring mvc反对并且会嵌入一个tomcat) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>Thymeleaf 依赖(提供了以html作为页面模板进行解析和操作的相干对象) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>第三步:启动我的项目检测控制台启动状态是否OK static 目录剖析及利用static 目录为springboot工程创立时增加了web依赖当前主动创立的目录,此目录中能够存储html、css、js、image,这些资源能够在启动服务器当前,间接在浏览器进行拜访。例如:第一步:在static目录下创立一个index.html页面,代码如下: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>The First Html Page</h1></body></html>第二步:启动服务器并间接进行拜访测试,如图所示 templates 目录剖析及利用templates 目录为springboot工程创立时增加了thymeleaf依赖当前主动创立的目录,此目录中要存储一些html模板,这个模板页面不能间接通过浏览器url进行拜访,须要基于后端控制器,在办法中定义页面响应,例如: 第一步:定义TemplateController及办法,代码如下: package com.cy.pj.health.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class TemplateController { @RequestMapping("doTemplateUI") public String doTemplateUI(){ return "default"; }}第二步:在templates目录中定义模板页面default.html,代码如下: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>The Default Template page</h1></body></html>其中,如果default.html要在放在templates子目录中,则还须要在配置文件中配置thymeleaf的前缀,例如: ...

December 9, 2020 · 2 min · jiezi

关于spring-mvc:SpringMVC是如何处理请求的

SpringMVC到底是如何解决申请的?很多人会用 SpringMVC,但对它的解决申请的形式并不分明,当咱们学习一个常识的时候,理解它会让咱们更好地应用它,上面咱们来看看 SpringMVC 是如何解决申请的。 申请流程的形式先上图: Spring MVC 框架也是一个基于申请驱动的 Web 框架,并且应用了前端控制器模式(是用来提供一个集中的申请解决机制,所有的申请都将由一个繁多的处理程序解决来进行设计,再依据申请映射规定分发给相应的页面控制器(动作/处理器)进行解决。首先让咱们整体看一下 Spring MVC 解决申请的流程: 首先用户发送申请,申请被 SpringMVC前端控制器(DispatherServlet)捕捉;前端控制器(DispatherServlet)对申请 URL 解析获取申请 URI,依据 URI,调用 HandlerMapping;前端控制器(DispatherServlet)取得返回的 HandlerExecutionChain(包含 Handler 对象以及 Handler 对象对应的拦截器);DispatcherServlet 依据取得的 HandlerExecutionChain,抉择一个适合的 HandlerAdapter。(附注:如果胜利取得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…) 办法);HandlerAdapter 依据申请的 Handler 适配并执行对应的 Handler;HandlerAdapter 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充 Handler 的入参过程中,依据配置,Spring 将做一些额定的工作:HttpMessageConveter:将申请音讯(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息; 数据转换:对申请音讯进行数据转换。如 String 转换成 Integer、Double 等; 数据格式化:如将字符串转换成格式化数字或格式化日期等; 数据验证: 验证数据的有效性(长度、格局等),验证后果存储到 BindingResult 或 Error 中); Handler 执行结束,返回一个 ModelAndView (即模型和视图)给 HandlerAdaptor;HandlerAdaptor 适配器将执行后果 ModelAndView 返回给前端控制器;前端控制器接收到 ModelAndView 后,申请对应的视图解析器;视图解析器解析 ModelAndView 后返回对应 View;渲染视图并返回渲染后的视图给前端控制器;最终前端控制器将渲染后的页面响应给用户或客户端。案例实操SpringMVC 申请执行源码解读对于 SpringMVC 我的项目所有的申请入口(动态资源除外)这里都是从 web.xml 文件配置的前端控制器 DispatcherServlet 开始: ...

December 8, 2020 · 7 min · jiezi

关于spring-mvc:SpringMVC中转发和重定向的区别

转发和重定向相同点都是web开发中资源跳转的形式。 不同点转发:是服务器外部的跳转,浏览器的地址栏不会发生变化。从一个页面到另一个页面的跳转还是同一个申请,也即是只有一个申请响应。能够通过request域来传递对象。重定向:是浏览器主动发动对跳转指标的申请,浏览器的地址栏会发生变化。从一个页面到另一个页面的跳转是不同的申请,也即是有两个或两个以上的不同的申请的响应。无奈通过request域来传递对象。 在SpringMVC中实现转发和重定向 (1)在SpringMVC中依然以传统形式进行转发和重定向上面的代码中login.jsp就是跳转后的页面转发: requst.getRequestDispatcher("login.jsp").forword(request,response);重定向: response.sendRedirect("login.jsp");(2)SpringMVC提供了便捷的转发和重定向的形式 //转发@RequestMapping("/forward")public String forword(){ return "forward:/index.jsp";}//重定向@RequestMapping("redirect")public String redirect(){ return "redirect:/index.jsp";}

December 5, 2020 · 1 min · jiezi

关于spring-mvc:SpringMvc路径参数和url的两种实现方式

一、申请参数 申请参数采纳key = value模式,并用“&”分隔。例如上面的URL带有名为name和pwd的申请参数。 localhost:9090/showUser?name=spring&pwd=spring 在传统的servlet编程中,能够应用HttpServletRequest的getParameter办法来获取申请参数值。 String name = httpServletRequest.getParameter(“name”); Spring MVC 提供了一个更简略的办法来获取申请参数:通过注解@RequestParam来正文办法参数。依据下面的URL,编写一个映射函数。 @RequestMapping(value="/showUser/") public String testRequestParam(@RequestParam String name, @RequestParam String pwd, Map<String, Object> model){ model.put("name", name); model.put("pwd", pwd); return "showUser"; }运行后果如下: 二、门路参数门路参数相似申请参数,但没有key局部,只是一个值。例如上面的URL: http://localhost:9090/showUser/spring其中的spring是示意用户的明码字符串。在Spring MVC中,spring被作为门路变量用来发送一个值到服务器。Sping 3当前Spring 3当前反对注解@PathVariable用来接管门路参数。为了应用门路变量,首先须要在RequestMapping注解的值属性中增加一个变量,该变量必须放在花括号之间,例如:@RequestMapping(value= “/showUser/{pwd}”)而后在办法签名中加上@PathVariable注解。具体代码如下: @RequestMapping(value= "/showUser/{pwd}") public String testPathVariable(@PathVariable(name="pwd") String password, Map<String, Object> model){ model.put("pwd", password); return "showUser"; }运行后果: 能够在申请映射中应用多个门路变量。例如,上面定义了userId和orderId两个门路变量。@RequestMapping(value= “/showUser/{userId}/{orderId}”)。

December 5, 2020 · 1 min · jiezi

关于spring-mvc:springMVC的工作流程

1.springmvc工作流程图 2.springmvc工作流程1、 用户向服务端发送一次申请,这个申请会先到前端控制器DispatcherServlet(也叫地方控制器)。2、DispatcherServlet接管到申请后会调用HandlerMapping处理器映射器。由此得悉,该申请该由哪个Controller来解决(并未调用Controller,只是得悉)3、DispatcherServlet调用HandlerAdapter处理器适配器,通知处理器适配器应该要去执行哪个Controller4、HandlerAdapter处理器适配器去执行Controller并失去ModelAndView(数据和视图),并层层返回给DispatcherServlet5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,而后返回真正的视图。6、DispatcherServlet将模型数据填充到视图中7、DispatcherServlet将后果响应给用户3.组件阐明 DispatcherServlet:前端控制器,也称为地方控制器,它是整个申请响应的控制中心,组件的调用由它对立调度。HandlerMapping:处理器映射器,它依据用户拜访的 URL 映射到对应的后端处理器 Handler。也就是说它晓得解决用户申请的后端处理器,然而它并不执行后端处理器,而是将处理器通知给中央处理器。HandlerAdapter:处理器适配器,它调用后端处理器中的办法,返回逻辑视图 ModelAndView 对象。ViewResolver:视图解析器,将 ModelAndView 逻辑视图解析为具体的视图(如 JSP)。Handler:后端处理器,对用户具体申请进行解决,也就是咱们编写的 Controller 类。组件具体阐明:1、前端控制器DispatcherServlet(不须要工程师开发),由框架提供作用:接管申请,响应后果,相当于转发器,中央处理器。有了dispatcherServlet缩小了其它组件之间的耦合度。用户申请达到前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程管制的核心,由它调用其它组件解决用户的申请,dispatcherServlet的存在升高了组件之间的耦合性。 2、处理器映射器HandlerMapping(不须要工程师开发),由框架提供作用:依据申请的url查找HandlerHandlerMapping负责依据用户申请找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射形式,例如:配置文件形式,实现接口方式,注解形式等。 3、处理器适配器HandlerAdapter作用:依照特定规定(HandlerAdapter要求的规定)去执行Handler通过HandlerAdapter对处理器进行执行,这是适配器模式的利用,通过扩大适配器能够对更多类型的处理器进行执行。 4、处理器Handler(须要工程师开发)留神:编写Handler时依照HandlerAdapter的要求去做,这样适配器才能够去正确执行HandlerHandler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的管制下Handler对具体的用户申请进行解决。因为Handler波及到具体的用户业务申请,所以个别状况须要工程师依据业务需要开发Handler。 5、视图解析器View resolver(不须要工程师开发),由框架提供作用:进行视图解析,依据逻辑视图名解析成真正的视图(view)View Resolver负责将处理结果生成View视图,View Resolver首先依据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最初对View进行渲染将处理结果通过页面展现给用户。 springmvc框架提供了很多的View视图类型,包含:jstlView、freemarkerView、pdfView等。个别状况下须要通过页面标签或页面模版技术将模型数据通过页面展现给用户,须要由工程师依据业务需要开发具体的页面。 6、视图View(须要工程师开发jsp...)View是一个接口,实现类反对不同的View类型(jsp、freemarker、pdf...) 外围架构的具体流程步骤如下:1、首先用户发送申请——>DispatcherServlet,前端控制器收到申请后本人不进行解决,而是委托给其余的解析器进行解决,作为对立拜访点,进行全局的流程管制;2、DispatcherServlet——>HandlerMapping, HandlerMapping 将会把申请映射为HandlerExecutionChain 对象(蕴含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易增加新的映射策略;3、DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而反对多种类型的处理器,即适配器设计模式的利用,从而很容易反对很多类型的处理器;4、HandlerAdapter——>处理器性能解决办法的调用,HandlerAdapter 将会依据适配的后果调用真正的处理器的性能解决办法,实现性能解决;并返回一个ModelAndView 对象(蕴含模型数据、逻辑视图名);5、ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其余视图技术;6、View——>渲染,View会依据传进来的Model模型数据进行渲染,此处的Model理论是一个Map数据结构,因而很容易反对其余视图技术;7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程完结。 下边两个组件通常状况下须要开发: Handler:处理器,即后端控制器用controller示意。 View:视图,即展现给用户的界面,视图中通常须要标签语言展现模型数据。 在将SpringMVC之前咱们先来看一下什么是MVC模式 MVC:MVC是一种设计模式 MVC的原理图:剖析: M-Model 模型(实现业务逻辑:有javaBean形成,service+dao+entity) V-View 视图(做界面的展现  jsp,html……) C-Controller 控制器(接管申请—>调用模型—>依据后果派发页面) springMVC是什么:  springMVC是一个MVC的开源框架,springMVC=struts2+spring,springMVC就相当于是Struts2加上sring的整合,然而这里有一个纳闷就是,springMVC和spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说,springMVC是spring的一个后续产品,其实就是spring在原有根底上,又提供了web利用的MVC模块,能够简略的把springMVC了解为是spring的一个模块(相似AOP,IOC这样的模块),网络上常常会说springMVC和spring无缝集成,其实springMVC就是spring的一个子模块,所以基本不须要同spring进行整合。 SpringMVC的原理图: 看到这个图大家可能会有很多的纳闷,当初咱们来看一下这个图的步骤:(能够比照MVC的原理图进行了解) 第一步:用户发动申请到前端控制器(DispatcherServlet) 第二步:前端控制器申请处理器映射器(HandlerMappering)去查找处理器(Handle):通过xml配置或者注解进行查找 第三步:找到当前处理器映射器(HandlerMappering)像前端控制器返回执行链(HandlerExecutionChain) 第四步:前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler) 第五步:处理器适配器去执行Handler 第六步:Handler执行完给处理器适配器返回ModelAndView 第七步:处理器适配器向前端控制器返回ModelAndView 第八步:前端控制器申请视图解析器(ViewResolver)去进行视图解析 第九步:视图解析器像前端控制器返回View 第十步:前端控制器对视图进行渲染 第十一步:前端控制器向用户响应后果 了解springMVC中的几个组件: 前端控制器(DispatcherServlet):接管申请,响应后果,相当于电脑的CPU。 ...

December 1, 2020 · 1 min · jiezi

关于spring-mvc:SSMCookieSession拦截器Interceptor

1 CookieCookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区倒退的一种机制。 Cookie实际上是一小段的文本信息。客户端申请服务器,如果服务器须要记录该用户状态,就应用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再申请该网站时,浏览器把申请的网址连同该Cookie一起提交给服务器。服务器查看该Cookie,以此来识别用户状态。服务器还能够依据须要批改Cookie的内容。 单点登录中可利用cookie设置实现。 可在浏览器中查看cookie,cookie不能跨域。一对一的关系。 1.1 设置CookieCookie常识介绍: 1.cookie.setPath("/") 代表根目录无效 url1:www.jt.com/addUser url2:www.jt.com/user/addUser2.cookie.setDomain("域名地址") cookie在哪些域名中共享 例子1:cookie.setDomain("www.jt.com");//只有在www.jt.com中共享 cookie.setDomain("jt.com");//在jt.com中共享3.cookie.setMaxAge(30*24*60*60);//让cookie30天无效。4.Cookie cookie = new Cookie("JT_TICKET",uuid); 设置cookie的name和值例如: @RestControllerpublic class UserController { @RequestMapping("/login") public String login(String username, HttpServletResponse response) { //创立cookie Cookie cookie = new Cookie("username", username); //把cookie返回给浏览器 response.addCookie(cookie); return "设置cookie"; }}1.2 读取Cookie@RestControllerpublic class OrderController { @RequestMapping("/getOrder") public String getOrder(HttpServletRequest request) { //读取所有cookie Cookie[] cookies = request.getCookies(); String string = ""; if (cookies != null) { //遍历cookie for (Cookie cookie : cookies) { //取cookie名 String cookieName = cookie.getName(); //取cookie值 String cookieValue = cookie.getValue(); string = string + cookieName + cookieValue; } } return string; }1.3 “删除”Cookiecookie不能被动删除,如需删除cookie,可从新设置cookie,将无效工夫改为0即可。 ...

November 28, 2020 · 2 min · jiezi

关于spring-mvc:这份SpringMVC执行原理笔记建议做java开发的好好看看总结的很详细

什么是SpringMVC?Spring MVC属于SpringFrameWork的后续产品,曾经交融在Spring Web Flow外面。Spring 框架提供的web模块,蕴含了开发Web 应用程序的全功能 MVC 模块。从而在应用Spring进行Web开发时,能够抉择应用Spring的SpringMVC框架。集成其余WEB MVC开发框架,如Struts、Struts2等。SpringMVC是Web层的MVC开发框架,属于Spring框架的Web模块中的一个局部。 基于SpringMVC案例创立webapp我的项目、欠缺我的项目构造、导入依赖<!-- 配置开发SpringMVC所以来的jar包 --><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.5.RELEASE</version></dependency><!-- 配置ServletAPI依赖 --><!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --><dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope></dependency><!--配置JSP依赖包--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.2.1</version> <scope>provided</scope></dependency>#### 在web.xml文件中配置中央处理器(DispatcherServlet) <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!-- 留神:/前面没有* --> <url-pattern>/</url-pattern> </servlet-mapping>创立自定义控制器类package qing;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class StudentController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(); mav.addObject("info", "hello,小李同学"); mav.setViewName("test.jsp"); return mav; }}在resources文件中编写SpringMVC.xml配置文件<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置URL解析器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- 配置管制适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- 配置自定义控制器 --> <!-- name:自定义控制器拜访门路 class:包名+类名 --> <bean name="/stu" class="qing.StudentController"></bean> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=""></property> </bean></beans>在web.xml配置文件中加载SpringMVC.xml文件<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:SpringMVC.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>创立test.jsp文件<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %><html><head> <title>欢送应用SpringMVC</title></head><body> <h1>${info}</h1></body></html>部署本地服务器测试http://localhost:8080/stu ...

November 27, 2020 · 2 min · jiezi

关于spring-mvc:SpringMVC到底是如何处理请求的

很多人会用 SpringMVC,但对它的解决申请的形式并不分明,当咱们学习一个常识的时候,理解它会让咱们更好地应用它,上面咱们来看看 SpringMVC 是如何解决申请的。 申请流程的形式先上图: Spring MVC 框架也是一个基于申请驱动的 Web 框架,并且应用了前端控制器模式(是用来提供一个集中的申请解决机制,所有的申请都将由一个繁多的处理程序解决来进行设计,再依据申请映射规定分发给相应的页面控制器(动作/处理器)进行解决。首先让咱们整体看一下 Spring MVC 解决申请的流程: 首先用户发送申请,申请被 SpringMVC前端控制器(DispatherServlet)捕捉;前端控制器(DispatherServlet)对申请 URL 解析获取申请 URI,依据 URI,调用 HandlerMapping;前端控制器(DispatherServlet)取得返回的 HandlerExecutionChain(包含 Handler 对象以及 Handler 对象对应的拦截器);DispatcherServlet 依据取得的 HandlerExecutionChain,抉择一个适合的 HandlerAdapter。(附注:如果胜利取得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(...) 办法);HandlerAdapter 依据申请的 Handler 适配并执行对应的 Handler;HandlerAdapter 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充 Handler 的入参过程中,依据配置,Spring 将做一些额定的工作:HttpMessageConveter:将申请音讯(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息; 数据转换:对申请音讯进行数据转换。如 String 转换成 Integer、Double 等; 数据格式化:如将字符串转换成格式化数字或格式化日期等; 数据验证: 验证数据的有效性(长度、格局等),验证后果存储到 BindingResult 或 Error 中); Handler 执行结束,返回一个 ModelAndView (即模型和视图)给 HandlerAdaptor;HandlerAdaptor 适配器将执行后果 ModelAndView 返回给前端控制器;前端控制器接收到 ModelAndView 后,申请对应的视图解析器;视图解析器解析 ModelAndView 后返回对应 View;渲染视图并返回渲染后的视图给前端控制器;最终前端控制器将渲染后的页面响应给用户或客户端。案例实操SpringMVC 申请执行源码解读对于 SpringMVC 我的项目所有的申请入口(动态资源除外)这里都是从 web.xml 文件配置的前端控制器 DispatcherServlet 开始: ...

November 20, 2020 · 7 min · jiezi

关于spring-mvc:SpringMVC源码分析

弱小的DispatcherServlet还记得在web.xml中配置的DispatcherServlet吗?其实那个就是SpringMVC框架的入口,这也是struts2和springmvc不同点之一,struts2是通过filter的,而springmvc是通过servlet的。看下servlet的结构图 从下面这张图很显著能够看出DispatcherServlet和Servlet以及Spring的关系。而咱们明天的重点就从DispatchServlet说起。 在剖析之前我用SpringBoot搭建了一个很简略的后盾我的项目,用于剖析。代码如下 import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;@Data@Builder@AllArgsConstructorpublic class User {private Integer id;private String name;private Integer age;private String address;public User() {}}/*** @author generalthink*/@RestController@RequestMapping("/user")public class UserController {@RequestMapping(value = "/{id}",method = RequestMethod.GET)public User getUser(HttpServletRequest request,@PathVariable Integer id) {//创立一个user,不走数据库只是为了剖析springmvc源码User user = User.builder().id(id).age(ThreadLocalRandom.current().nextInt(30)).name("zzz" + id).address("成都市").build();return user;}@RequestMapping(value = "/condition",method = RequestMethod.GET)public User getByNameOrAge(@RequestParam String name,@RequestParam Integer age) {User user = User.builder().name(name).age(age).address("成都市").id(2).build();return user;}@PostMappingpublic Integer saveUser(@RequestBody User user) {Integer id = user.getName().hashCode() - user.getAge().hashCode();return id > 0 ? id : -id;}}这里为了不便调试把关注点更多集中在SpringMVC源码中,所以这里的数据都是伪造的。而且这里的关注点也集中到应用注解的Controller(org.springframework.stereotype.Controller),而不是Controller接口(org.springframework.web.servlet.mvc.Controller),这两者的区别次要在意一个只用标注注解,一个须要实现接口,然而它们都能实现解决申请的基本功能。咱们都晓得拜访servlet的时候默认是拜访service办法的,所以咱们将断点打在HttpServlet的service办法中,此时查看整个调用栈如下从这里咱们也晓得了申请时如何从servlet到了DispatcherServlet的,咱们先来看一下DispatcherServlet的doDiapatch的办法逻辑,这里把外围逻辑列出来了,把其余的一些非核心逻辑移除了 ...

November 11, 2020 · 2 min · jiezi

关于spring-mvc:SpringBoot强化篇四Spring-MVC框架的整合及原理分析

Spring MVC 简介在大型软件系统设计时,业务个别会绝对简单,如果所有业务实现的代码都纠缠在一起,会呈现逻辑不清晰、可读性差,保护艰难,改变一处就牵一发而动全身等问题。为了更好解决这个问题就有了咱们当初常说的分层架构设计。 MVC 是什么MVC是一种软件架构设计思维,基于MVC架构将咱们的应用软件进行分层设计和实现,例如能够分为视图层(View),管制层(Controller),模型层(Model),通过这样的分层设计让咱们程序具备更好的灵活性和可可扩展性.因为这样能够将一个简单应用程序进行简化,实现各司其职,各尽所能.比拟适宜一个大型利用的开发.▪ 视图(View) - UI设计人员进行图形界面设计,负责实现与用户交互。▪ 控制器(Controller)- 负责获取申请,解决申请,响应后果。▪ 模型(Model) - 实现业务逻辑,数据逻辑实现。 Spring MVC 概述Spring MVC是MVC设计思维在Spring框架中的一种实现,基于这样的思维spring框架设计了一些相干对象,用于更好的基于MVC架构解决申请和响应,其繁难架构如图所示:1.前端控制器 DispatcherServlet是客户端所有申请解决的入口,负责申请转发。2.处理器映射器 RequestMapping负责存储申请url到后端handler对象之间的映射。3.处理器适配器 Handler 用于解决DispatcherServlet对象转发过去的申请数据。4.视图解析器 ViewResolver负责解决所有Handler对象响应后果中的view。 Spring MVC 疾速入门筹备工作第一步:创立我的项目module,根本信息如图所示: 第二步:增加我的项目依赖(能够在module创立时,也能够创立后),代码如下: Spring Web 依赖(提供了spring mvc反对并且会嵌入一个tomcat) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>Thymeleaf 依赖(提供了以html作为页面模板进行解析和操作的相干对象) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>static 目录剖析及利用static 目录为springboot工程创立时增加了web依赖当前主动创立的目录,此目录中能够存储html、css、js、image,这些资源能够在启动服务器当前,间接在浏览器进行拜访。 templates 目录剖析及利用templates 目录为springboot工程创立时增加了thymeleaf依赖当前主动创立的目录,此目录中要存储一些html模板,这个模板页面不能间接通过浏览器url进行拜访,须要基于后端控制器,在办法中定义页面响应其中,如果default.html要在放在templates子目录中,则还须要在配置文件中配置thymeleaf的前缀 #server portserver.port=80#spring webspring.thymeleaf.prefix=classpath:/templates/health/spring.thymeleaf.suffix=.html#spring thymeleafspring.thymeleaf.cache=false定义HealthController类来测试 package com.cy.pj.health.controller;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletResponse;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;@Controllerpublic class HealthController {//Handler对象 来解决DispatcherServlet散发过去的申请 //三种状况 //1.只返回页面 //2.返回json字符串 //3.返回页面加参数 @RequestMapping("/doPrint") @ResponseBody public void doPrint(HttpServletResponse response) throws Exception{ Map<String,Object> map =new HashMap<>(); map.put("username", "tony"); map.put("state", true); //return map ; //将map中的数据转换成json格局的字符串,底层实现如下 ObjectMapper om=new ObjectMapper(); String jsonStr=om.writeValueAsString(map);//jackson中转换json字符串的办法 System.out.println("jsonStr="+jsonStr); //将字符串响应到客户端 response.setCharacterEncoding("utf-8");//批改编码方式 response.setContentType("text/html;charset=utf-8");//通知客户端咱们的编码格局让其以这种形式解析数据 PrintWriter pw = response.getWriter();//写入响应流中 pw.println(jsonStr); } @RequestMapping("/doHealth") public String doHealth(Model model) { model.addAttribute("username","张三"); model.addAttribute("state","亚健康"); return "default"; //返回的字符串交给ViewResolver视图解析器,会主动剖析,传参且出现页面 } @RequestMapping("/health.html") @ResponseBody //应用此注解形容管制办法时,用于通知spring框架,这个办法返回值能够依照特定格局(例json字符串)进行转换,来响应客户端 //将转换当前的后果写到response对象的响应体中 //f昂发的返回值不再封装为ModelAndView对象,不会再交给视图解析器进行解析,而是间接基于response对象响应到客户端 public Map<String, Object> doHealth(){ Map<String,Object> map =new HashMap<>(); map.put("username", "tony"); map.put("state", true); return map ; } //public ModelAndView doHealth(){//此办法由DispatcherServlet对象通过反射调用 //ModelAndView mv =new ModelAndView(); //mv.setViewName("default");//viewname //mv.addObject("username","李四"); //mv.addObject("state","亚健康");//传的是个对象,所以能够传的不止字符串 //return mv; //1.返回值会交给DispatcherServlet对象进行解决 //2.DispatcherServlet对象会调用viewresolver对后果进行解析 //2.1基于viewname找对应的view页面(prefix+viewname+suffix) //2.2将model中的数据填充到view页面上 //2.3返回一个带有module数据的页面给DispatcherServlet //3.DispatcherServlet将带有model数据的页面返回给客户端 //public String doHealth(){ // return "default" ;// 能够间接返回对应名字的页面 // }}JSON数据响应咱们有一业务不须要页面,只须要将响应数据转换为json,而后响应到客户端,如何实现呢?第一步:定义ResponseResult对象用于封装响应数据,例如: ...

November 10, 2020 · 2 min · jiezi

关于spring-mvc:精通Spring-MVC4pdf

关注公众号“Java后端技术全栈”** 回复“面试”获取全套大厂面试材料 Spring MVC 属于 Spring Framework 的衍生产品,曾经交融在 Spring Web Flow 外面。  Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。Spring MVC 4 是以后比拟罕用的版本,在泛滥个性上有了进一步的晋升。 最近很多小伙伴问我要一些Spring MVC 的相干材料,于是我翻箱倒柜,找到了这本能够教咱们从头开始构建一个有用的Web利用的电子书——《精通Spring MVC4》。 材料介绍 本书中从头开始构建了一个残缺的 Web 利用。全书共10 章,别离介绍了疾速搭建 Spring Web 利用、精通 MVC 构造、解决表单和简单的 URL 映射、文件上传与错误处理、创立 RESTful 利用、爱护利用、单元测试与验收测试、优化申请、将 Web 利用部署到云等内容, 循序渐进地解说了 Spring MVC 4 的开发技巧。 本书最适宜曾经相熟 Spring 编程基础知识并迫切希望扩大其 Web 技能的开发人员。通过浏览本书,读者将深度把握 Spring MVC 的各项个性及实用技巧。  最次要的是,这份材料不是扫描版,还能够复制哟。 如何获取? 辨认二维码并关注公众号「Java后端技术全栈」;在公众号后盾回复关键字「505」。

November 5, 2020 · 1 min · jiezi

关于spring-mvc:Spring-MVC-源码之请求的执行流程

Spring MVC 源码之申请的执行流程 DispatcherServletSpringMVC外围就是DispatcherServlet,所有得申请都会转发到DispatcherServlet,而后再通过DispatcherServlet执行具体得管制层(Handler)返回ModelAndView给客户端视图展现。 DispatcherServlet其实就是一个Servlet类,无非就是包装一层,通过url可能映射找到咱们得SpringMvc中定义得申请办法。 类的集成关系DispatcherServlet继承FrameworkServlet继承HttpServlet 面向基本上思维 重写 先走父类 ,在走子类。 得出答案:先看HttpServlet再找到咱们最初的子类 当咱们第一次申请一个地址的时候,如果可能拜访,他会返回一个200代表拜访胜利,此时应答头信息中会有一个 Last-Modified 代表服务器这个文件的最初批改工夫。 当咱们再次申请的时候,如果申请过了,就会在申请头,有一个If-Modified-Since的值,这时候传到服务器,服务器就会拿这个值和上次批改的工夫比照,如果小于上次批改的工夫,阐明服务器上的文件被批改过,就再次从服务器进行下载,返回200 如果没有批改就像上图一样,返回一个304,代表客户端曾经执行了GET,但文件未变动。 既然是Servlet类,那么他有一个最终的办法,就是service()办法,他是Servlet最外围的办法。 HttpServlet#service protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < lastModified) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }maybeSetLastModified(resp, lastModified); ...

November 2, 2020 · 7 min · jiezi

关于spring-mvc:Spring-MVC-到-Spring-Boot-的简化之路

背景从Servlet技术到Spring和Spring MVC,开发Web利用变得越来越简捷。然而Spring和Spring MVC的泛滥配置有时却让人望而生畏,置信有过Spring MVC开发教训的敌人能粗浅领会到这一苦楚。因为即便是开发一个Hello-World的Web利用,都须要咱们在pom文件中导入各种依赖,编写web.xml、spring.xml、springmvc.xml配置文件等。特地是须要导入大量的jar包依赖时,咱们须要在网上查找各种jar包资源,各个jar间可能存在着各种依赖关系,这时候又得下载其依赖的jar包,有时候jar包间还存在着严格的版本要求,,所以当咱们只是想开发一个Hello-World的超简略的Web利用时,却把极大局部的工夫在花在了编写配置文件和导入jar包依赖上,极大地影响了咱们的开发效率。所以为了简化Spring繁冗的配置,Spring Boot应运而生。正如Spring Boot的名称一样,一键启动,Spring Boot提供了主动配置性能,为咱们提供了开箱即用的性能,使咱们将重心放在业务逻辑的开发上。那么Spring Boot又是怎么简化Spring MVC的呢?Spring Boot和Spring、Spring MVC间又是怎么的关系呢?Spring Boot又有什么新特点呢?接下来,让咱们走进Spring MVC 到Spring Boot的简化之路,或者你就能找到这些答案。 Spring vs Spring MVC vs Spring BootSpring Boot和Spring、Spring MVC不是竞争关系,Spring Boot使咱们更加容易应用Spring和Spring MVCSpring FrameWorkSpring FrameWork解决的外围问题是什么 Spring框架的最重要个性是依赖注入,所有的Spring模块的外围都是依赖注入(DI)或管制反转(IOC)。为什么很重要呢,因为当咱们应用DI或IOC时,咱们能够使利用失去解耦。咱们来看一个简略的例子:没有依赖注入的例子: @RestControllerpublic class WelcomeController { private WelcomeService service = new WelcomeService(); @RequestMapping("/welcome") public String welcome() { return service.retrieveWelcomeMessage(); }}WelcomeService service = new WelcomeService(); 意味着WelcomeController类与WelcomeService类紧密结合在一起,耦合度高。复制代码应用依赖注入的例子: @Componentpublic class WelcomeService { //Bla Bla Bla}@RestControllerpublic class WelcomeController { @Autowired private WelcomeService service; @RequestMapping("/welcome") public String welcome() { return service.retrieveWelcomeMessage(); }}依赖注入使世界看起来更简略,咱们让Spring 框架做了辛勤的工作:@Component:咱们通知Spring框架-嘿,这是一个你须要治理的bean@Autowired:咱们通知Spring框架-嘿,找到这个特定类型的正确匹配并主动装入它复制代码如果感觉看完文章有所播种的话,能够关注我一下哦知乎:秃顶之路 b站:linux亦有归途 每天都会更新咱们的公开课录播以及编程干货和大厂面经或者间接点击链接c/c++ linux服务器开发高级架构师来课堂上跟咱们讲师面对面交换须要大厂面经跟学习纲要的小伙伴能够加群973961276获取 ...

October 31, 2020 · 2 min · jiezi

关于spring-mvc:浅谈SpringMVC处理流程

1.解决流程图 2.流程阐明* 一个申请匹配前端控制器DispatcherServlet的申请映射门路(在web.xml中指定),WEB容器将该申请转交给DispatcherServlet解决* DispatcherServlet接管到申请后,依据申请信息交给处理器映射器(HandlerMapping)* HandlerMapping依据用户的url申请查找匹配该url的Handler,并返回一个执行链* DispatcherServlet再申请处理器适配器HandlerAdapter调用雷同的Handler进行解决并返回ModelAndView给DispatcherServlet* DispatcherServlet将ModelAndView申请ViewResolver(视图解析器)解析,返回具体的view* DispatcherServlet对View进行渲染视图(行将模型数据填充至视图中)* DispatcherServlet将页面响应给客户3.组件阐明DispatcherServlet:前端控制器 用户申请达到前端控制器,它就相当于mvc模式中的c(管制层),DispatcherServlet是整个流程管制的核心,由它调用其它组件解决用户的申请,DispatcherServlet的存在升高了组件之间的耦合性。HandlerMapping:处理器映射器 HandlerMapping负责依据用户申请url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射形式,例如:配置文件形式,实现接口方式,注解形式等。Handler:处理器 Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的管制下Handler对具体的用户申请进行解决。因为Handler设计到具体的用户业务申请,所以个别状况下须要程序员依据业务需要开发Handler。HandlerAdapter:处理器适配器 通过HandlerAdapter对处理器进行执行,这是适配器模式的利用,通过扩大适配器能够对更多类型的处理器进行执行。ViewResolver:视图解析器 ViewResolver负责将解决的后果生成View视图,ViewResolver首先依据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最初对View进行渲染将处理结果通过页面展现给用户。View:视图 springmvc框架提供了很多的view视图类型的反对,包含:jstlView,freemakerView,pdfView等。咱们最常见的视图就是jsp,个别状况下须要页面标签或者页面模版技术将模型数据通过页面展现给用户,须要程序员依据业务需要开发具体的页面。

October 30, 2020 · 1 min · jiezi

关于spring-mvc:Spring-MVC的配置和原理

SpringMVC的配置和原理:1.Spring MVC的配置:1.在pom.xml中引入springmvc所须要的jar包: <dependencies> <!-- Spring MVC的jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.3.RELEASE</version> </dependency> <!-- servlet 和 jsp 的jar包 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> </dependencies>2.在web.xml中 配置前端控制器 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><!-- 配置springmvc前端控制器(DispatcherServlet),将所有申请交给springmvc来解决 --><servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置springmvc外围配置文件的地位,默认springmvc的配置文件在WEB-INF录下,默认的名字为springmvc-servlet.xml,如果要放在其余目录,则须要指定如下配置: --> <init-param> <!-- 这里配置的是固定值 --> <param-name>contextConfigLocation</param-name> <!-- 这里依据文件名和地位决定xml文件的门路 --> <param-value>classpath:springmvc-config.xml</param-value> </init-param></servlet><servlet-mapping> <!-- 此名字要与下面的name一样 --> <servlet-name>springmvc</servlet-name> <!--/*:拦挡动态web资源(html/css/JS/图片),包含JSP /:拦挡动态web资源,不包含JSP --> <url-pattern>/</url-pattern></servlet-mapping></web-app>3.创立并配置springmvc-config.xml ...

October 29, 2020 · 1 min · jiezi

关于spring-mvc:SpringMVC

待欠缺

October 25, 2020 · 1 min · jiezi

关于spring-mvc:SpringMVC

待欠缺

October 25, 2020 · 1 min · jiezi

关于spring-mvc:动吧旅游生态系统日志管理设计说明

1 日志治理设计说明1.1 业务设计说明本模块次要是实现对用户行为日志(例如谁在什么工夫点执行了什么操作,拜访了哪些办法,传递的什么参数,执行时长等)进行记录、查问、删除等操作。其表设计语句如下: CREATE TABLE `sys_logs` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT NULL COMMENT '登陆用户名', `operation` varchar(50) DEFAULT NULL COMMENT '用户操作', `method` varchar(200) DEFAULT NULL COMMENT '申请办法', `params` varchar(5000) DEFAULT NULL COMMENT '申请参数', `time` bigint(20) NOT NULL COMMENT '执行时长(毫秒)', `ip` varchar(64) DEFAULT NULL COMMENT 'IP地址', `createdTime` datetime DEFAULT NULL COMMENT '日志记录时间', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系统日志';1.2 原型设计说明基于用户需要,实现动态页面(html/css/js),通过动态页面为用户出现根本需要实现,如图-1所示。 图-1 阐明:如果客户对此原型进行了确认,后续则能够基于此原型进行研发。 1.3 API设计说明日志业务后盾API分层架构及调用关系如图-2所示: ...

October 21, 2020 · 8 min · jiezi

关于spring-mvc:动吧旅游生态系统day01

1我的项目简介1.1 概述动吧游览生态系统,应市场高端用户需要,公司决定开发这样的一套游览零碎,此零碎蕴含游览电商零碎(广告子系统,举荐子系统,评估子系统,商品子系统,订单子系统,…),游览分销零碎(分销商的治理),游览业务零碎(产品研发,计调服务,零碎权限管理子系统,..),,。。。 1.2 原型剖析基于用户需要,进行原型设计(基于html+css+js进行动态页面实现)。例如零碎登录页面: 零碎登录胜利页面(例如starter.html) 菜单展现页面 阐明:原型设计好当前,会与客户进行确认,确认好当前进行签字,而后就是设计和实现. 2 技术架构2.1 我的项目分层架构本我的项目应用层基于MVC设计思维,进行分层架构设计,其外围目标是将简单问题简单化,实现各司其职,各尽所能.而后基于“高内聚,低耦合”的设计思维,再实现各对象之间协同,从而进步零碎的可维护性,可扩展性。 其中: 1.凋谢接口层:可间接封装 Service 办法裸露成 RPC (近程过程调用)接口;也可通过 Web 封装成 http 接口;同时也可进行网关安全控制、流量管制等。 2.终端显示层:负责各个端的模板渲染并显示。以后次要是 thymeleaf 渲染,JS 渲染,挪动端展现等。 3.Web申请解决层:次要是对访问控制进行转发,申请参数校验,响应后果解决等 4.Service 层:绝对具体的业务逻辑服务层(外围业务,扩大业务)。 5.Manager 层:通用业务解决层,它有如下特色: 1) 对第三方平台封装的层,预处理返回后果及转化异样信息; 2) 对 Service 层通用能力的下沉,如缓存计划、中间件通用解决; 3) 与 DAO 层交互,对多个 DAO 的组合复用。 6.DAO 层:数据拜访层,与底层 MySQL、Oracle、Hbase 等进行数据交互。 7.内部接口或第三方平台:包含其它部门RPC凋谢接口,根底平台,其它公司的 HTTP 接口 阐明:对如上分层中波及到常识的点,逐渐增强。 总之:分层的目标就是将简单问题进行拆解,而后分而治,进而进步零碎的可扩展性以及可维护性。 2.2 API利用架构整体API利用架构: 3 技术整合3.1 环境筹备3.1.1 数据库初始化启动MySQL客户端并登陆,而后执行 1) set names utf8; 2) source d:/jtsys.sql ...

October 21, 2020 · 1 min · jiezi

关于spring-mvc:spring-mvc框架的理解

spring mvc?要想晓得什么是spring mvc首先要晓得什么是设计模式? 设计模式(Design Pattern)是一套被重复应用、少数人通晓的、通过分类的、代码设计教训的总结。 应用设计模式的目标:为了代码可重用性、让代码更容易被别人了解、保障代码可靠性。 设计模式使代码编写真正工程化; 设计模式是软件工程的基石脉络,如同大厦的构造一样。 设计模式就是一种模子,通过多年实际锻炼造成一套卓有成效的实现某个特定工作的步骤和形式。 例如:西凤酒的酿造过程,酿造工序,前后不能变,温差不能变,这样做就是好喝,略微改变就变滋味了。 再如,北京烤鸭,就是那样做,就是那些调料腌制,变量配比,滋味口感就是不如人家。 MVC设计模式MVC设计模式是一种通用的软件编程思维 在MVC设计模式中认为, 任何软件都能够分为三局部组成: (1)控制程序流转的控制器(Controller) (2)封装数据解决数据的模型(Model) (3)负责展现数据的视图(view) 并且在MVC设计思维中要求一个合乎MVC设计思维的软件应该保障下面这三局部互相独立,互不烦扰,每一个局部只负责本人善于的局部。 如果某一个模块发生变化,应该尽量做到不影响其余两个模块。这样做的益处是,软件的构造会变得更加的清晰,可读性强。有利于前期的扩大和保护,并且代码能够实现复用。 简介spring mvcSpringmvc是spring框架的一个模块,spring和springmvc无需两头整合层整合 Springmvc是一个基于mvc的web框架 spring mvc 执行的原理解析 (1).用户发送申请 至 前端控制器(DispatcherServlet); 提醒:DispatcherServlet的作用:接管申请,调用其它组件解决申请,响应后果,相当于转发器、中央处理器,是整个流程管制的核心 (2).前端控制器(DispatcherServlet)收到申请后调用处理器映射器(HandlerMapping) 处理器映射器(HandlerMapping)找到具体的Controller(能够依据xml配置、注解进行查找),并将Controller返回给DispatcherServlet; (3).前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器通过适配调用具体的Controller;(Controller--> service --> Dao --> 数据库) Controller执行实现后返回ModelAndView, 提醒:Model(模型数据,即Controller解决的后果,Map) View(逻辑视图名,即负责展现后果的JSP页面的名字) 处理器适配器(HandlerAdapter)将controller执行的后果(ModelAndView)返回给前端控制器(DispatcherServlet); (4).前端控制器(DispatcherServlet)将执行的后果(ModelAndView)传给视图解析器(ViewReslover) 视图解析器(ViewReslover)依据View(逻辑视图名)解析后返回具体JSP页面 (5).前端控制器(DispatcherServlet)依据Model对View进行渲染(行将模型数据填充至视图中); 前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。 其中整个过程中须要开发人员编写的局部有Controller、Service、Dao、View;

October 15, 2020 · 1 min · jiezi

关于spring-mvc:第六阶段-第三模块

/*是包含jsp为尾缀的 只有是负数启动的时候就会加载 视图渲染就是填充数据 tomcat8.5以上会解决get申请中文乱码的问题可是解决不了post申请的中文乱码 参数名要与name统一

October 6, 2020 · 1 min · jiezi

关于spring-mvc:SpringMVC

Spring MVC 简介 MVC是什么 mvc是一种软件架构设计思维,基于MVC架构将咱们的应用软件进行分层设计和实现, @ResponseBody 过后应用此注解形容管制层办法时,用于通知spring框架,这个办法返回字符串尽量转换为json字符串到客户端 理论我的项目中既有页面 还有数据 当应用此注解形容管制层办法时,用于spring框架,这个办法返回值能够依照特定格局(例如json)进行转换 而后将转换当前的后果写到response对象的响应体中 办法的返回值不在封装为ModelAndView对象,不会再交给解析器进行解析,而是间接基于response对象响应到客户端 背景剖析 在大型软件系统设计时,业务个别会绝对简单,例如所有的业务实现的代码都纠缠在一起,会突出 逻辑不清晰,可读性差,保护艰难,改变一处就牵一动员全身等问题。为了更好解决这个问题就有 了咱们当初常说的分层架构 MVC是什么 mvc是一种软件架构的设计思维,基于MVC架构将咱们的应用软件进行分层设计和实现,例如能够 分为视图层(view)管制层(controller),模型层(model),通过这样的分层设计让咱们的程序有更 好的灵活性,和可扩展性,因为这样能够讲一个简单的应用程序进行简化实现各司其职,各尽所能比拟适宜一些大型利用的开发。 Spring MVC概述 springmvc 是mvc 设计思维在spring框架中的一种实现,基于这样的思维spring框架设计一些相干 对象,用于更好的基于mvc架构解决和响应,其简略架构如下图所示 其中: 1)DispatcherServlet是负责客户端所有申请的一个解决的入口,负责申请和转发, 2)RequestMapping负责贮存申请url到后端服务器handler对象对象之间的映射。 3)Handler用于解决DispatcherServlet对象转发过去的申请数据。 4)ViewResolver负责解决所有的Handler对象响应后果中的view。 SpringMVC疾速入门 第一步 创立medule 第二步 创立依赖(能够在module创立时,也能够在创立后)代码如下 第三步 启动我的项目检测控制台启动状态是否为ok Statics目录剖析及利用 Statics目录为Springboot工程创立时增加web依赖当前主动创立的目录,此目录中能够贮存 html,css,js 等相干资源,这些资源能够在启动服务器当前,间接在浏览器上进行拜访。 例如: 第一步: 在statics目录下创立一个index.html(首页)页面,代码如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>The First Html Page</h1> </body> </html> 第二部:启动服务器并间接进行拜访测试 如图所示: templates目录剖析及利用 templates目录为springboot工程创立时天年假了thymelea当前主动创立的目录,此目录中要贮存 一些html模板,这个模板页面不能间接通过浏览器进行拜访,须要基于后端控制器,在办法中定义 ...

October 5, 2020 · 2 min · jiezi

关于spring-mvc:EasyUISpringMVC上传文件

成果 因为传入的url是一个假的,所以回显的图片和保留的图片不统一 1.jskingEditorParams : { filePostName : "uploadFile", uploadJson : '/pic/upload', dir : "image"},// 初始化图片上传组件initPicUpload : function(data){ $(".picFileUpload").each(function(i,e){ var _ele = $(e); _ele.siblings("div.pics").remove(); _ele.after(' <div class="pics"> <ul></ul> </div>'); // 回显图片 if(data && data.pics){ var imgs = data.pics.split(","); for(var i in imgs){ if($.trim(imgs[i]).length > 0){ _ele.siblings(".pics").find("ul").append("<li><a href='"+imgs[i]+"' target='_blank'><img src='"+imgs[i]+"' width='80' height='50' /></a></li>"); } } } $(e).click(function(){ var form = $(this).parentsUntil("form").parent("form"); KindEditor.editor(TT.kingEditorParams).loadPlugin('multiimage',function(){ var editor = this; editor.plugin.multiImageDialog({ clickFn : function(urlList) { var imgArray = []; KindEditor.each(urlList, function(i, data) { imgArray.push(data.url); form.find(".pics ul").append("<li><a href='"+data.url+"' target='_blank'><img src='"+data.url+"' width='80' height='50' /></a></li>"); }); form.find("[name=image]").val(imgArray.join(",")); editor.hideDialog(); } }); }); }); });}, /** * 初始化单图片上传组件 <br/> * 选择器为:.onePicUpload <br/> * 上传实现后会设置input内容以及在input前面追加<img> */ initOnePicUpload : function(){ $(".onePicUpload").click(function(){ var _self = $(this); KindEditor.editor(TT.kingEditorParams).loadPlugin('image', function() { this.plugin.imageDialog({ showRemote : false, clickFn : function(url, title, width, height, border, align) { var input = _self.siblings("input"); input.parent().find("img").remove(); input.val(url); input.after("<a href='"+url+"' target='_blank'><img src='"+url+"' width='80' height='50'/></a>"); this.hideDialog(); } }); });}); }2.jsp<tr> <td>商品图片:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton picFileUpload">上传图片</a> <input type="hidden" name="image"/> </td></tr>3.后端实现3.1封装ImageVO特定的格局信息{“error”:0,“url”:“图片的保留门路”,“width”:图片的宽度,“height”:图片的高度}依据easyUI的格局信息封装ImageVO类 ...

September 29, 2020 · 2 min · jiezi

关于spring-mvc:SpringMVC-用于接收参数的注解

如上图中所示:次要分为三个注解: @RequestParam:用于接管 get/post 申请提交的 键值对/表单 参数,个别在申请中传参中能够省略.@PathVariable:用于接管restful格调的申请门路参数,如:http://localhost:8080/123/aa/bb@RequestBody:用于残缺承受post申请协定体中的json数据@RequestBody能够了解为和@ResponseBody是一对的,@RequestBody用于接管json数据,@ResponseBody用于返回json数据

September 22, 2020 · 1 min · jiezi

关于spring-mvc:SpringMVC-参数格式

SpringMVC中参数格局阐明简略参数传值问题阐明:页面传参中 name属性必须与mvc中的数据保持一致.1.页面信息 <input type="text" name="name" value="二郎神"/><input type="text" name="age" value="3500"/>2.服务端接管 public String saveUser(String name,Integer age){....}利用对象的形式接管参数1.页面信息 <input type="text" name="name" value="二郎神"/><input type="text" name="age" value="3500"/>2.服务端接管 public String saveUser(User user){....}mvc为对象的援用赋值问题:如何解决重名提交的问题计划: 能够将对象进行封装,之后采纳对象援用赋值的形式实现该性能.注意事项: 属性的名称必须统一,否则赋值失败. 1.页面信息 <input type="text" name="name" value="二郎神"/><input type="text" name="age" value="3500"/><input type="text" name="dog.name" value="啸天犬"/><input type="text" name="dog.age" value="5000"/> 2.服务端接管 public class User { private String name; private Integer age; private Dog dog;}public class Dog{ private String name; private Integer age;}public String saveUser(User user){....}pojo对象定义理论我的项目中采纳为对象援用赋值的操作. 然而该属性不属于数据库,所以须要额定的配置.长久层若是采纳MP实现,须要在援用赋值的字段增加@TableField(exist=false) //入库操作疏忽该字段配置; 如果间接应用的mybatis,在sql语句中不写援用字段即可.

September 21, 2020 · 1 min · jiezi

关于spring-mvc:Spring-mvc处理web请求简易图解

外围组件剖析: DispatcherServlet :前端控制器, 解决申请的入口。HandlerMapping:映射器对象, 用于治理url与对应controller的映射关系。Controller:后端控制器-handler, 负责解决申请的管制逻辑。ViewResolver:视图解析器,解析对应的视图关系(前缀+viewname+后缀)。

August 4, 2020 · 1 min · jiezi

关于spring-mvc:Spring-mvc处理web请求简易图解

外围组件剖析: DispatcherServlet :前端控制器, 解决申请的入口。HandlerMapping:映射器对象, 用于治理url与对应controller的映射关系。Controller:后端控制器-handler, 负责解决申请的管制逻辑。ViewResolver:视图解析器,解析对应的视图关系(前缀+viewname+后缀)。

August 4, 2020 · 1 min · jiezi

关于spring-mvc:Spring-MVC-理解核心原理-实现轻量级Spring-MVC框架

波及知识点:slf4jjava annotation如何定义通过classloader获取java文件的门路等信息 - https://www.cnblogs.com/seven...map遍历 https://blog.csdn.net/tjcyjd/... 办法二class.forname实例化 https://www.cnblogs.com/shosk...java 反射中的调用办法 - https://www.cnblogs.com/qingc...java 获取我的项目门路的形式第一局部, 工程根底配置创立Dynamic web工程为工程增加runtime librariy. 目标: 为了实现servlet性能 (次要须要其中的servlet-api等jar文件) 此为servlet基础知识. 创立DispatcherServlet并继承HttpServletweb.xml中申明此dispatcherServlet, 目标: ①示意这是个会被tomcat容器辨认的servlet, ②拦挡所有申请 <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SpringSim2</display-name> <servlet> <servlet-name>springsim2</servlet-name> <servlet-class>com.spring.sim.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>springsim2</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>src下创立application.properties, 指定须要被扫描的包 path=com.spring.simweb.xml中将properties文件设置为启动时被load ⚠ 此步骤为可选, 在DispatcherServlet中申明也能够 此步实现后, web.xml不须要再改变 <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SpringSimv1</display-name> <servlet> <servlet-name>springsim</servlet-name> <servlet-class>pro.yizheng.DispatcherServlet</servlet-class> <!-- 指定配置文件 --> <init-param> <param-name>webXmlInitParam-properties</param-name> <param-value>application.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springsim</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>申明要用到的Annotation 波及到的annotation有: Autowired, Controller, RequestMapping, RequestParam, Service波及Annotation知识点这一步骤Annotation source code: ...

July 20, 2020 · 2 min · jiezi

Spring-Boot-2X四Spring-Boot-自定义-Web-MVC-配置

0.准备Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类。Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一个注解 @EnableWebMvc 以帮助我们减少配置 Bean 的声明。本文简单说明如何自定义 Web MVC 配置。首先需要使用 @Configuration 将 WebMvcConfig 类标注为 Spring 配置类,示例代码如下: @Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport { //通过重写配置方法覆盖}并在启动类上添加 @EnableWebMvc,代码如下: @SpringBootApplication@MapperScan("cn.zwqh.springboot.dao")@EnableWebMvc //启用 Spring MVC 配置public class SpringBootSsmThymeleafApplication { public static void main(String[] args) { SpringApplication.run(SpringBootSsmThymeleafApplication.class, args); }}1.静态资源配置Spring Boot 中默认的静态资源配置,是把类路径下的/static、/public、/resources 和 /METAINF/resources 目录或者 ServletContext 的根目录中的静态文件直接映射为 /**。它使用来自 Spring MVC 的ResourceHttpRequestHandler,以便您可以通过添加自己的WebMvcConfigurer并覆盖addResourceHandlers方法来修改该行为。示例代码如下: @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");//静态资源路径 css,js,img等 registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");//视图 registry.addResourceHandler("/mapper/**").addResourceLocations("classpath:/mapper/");//mapper.xml super.addResourceHandlers(registry); } 2.拦截器配置通过重写 addInterceptors() 方法,使用 InterceptorRegistry 注册类来添加拦截器 HandlerInterceptor。示例代码如下: ...

November 5, 2019 · 2 min · jiezi

Spring-Boot-2X三使用-Spring-MVC-MyBatis-Thymeleaf-开发-web-应用

前言Spring MVC 是构建在 Servlet API 上的原生框架,并从一开始就包含在 Spring 框架中。本文主要通过简述 Spring MVC 的架构及分析,并用 Spring Boot + Spring MVC + MyBatis (SSM)+ Thymeleaf(模板引擎) 框架来简单快速构建一个 Web 项目。 Web MVC 架构及分析MVC 三层架构如图所示,红色字体代表核心模块。其中 MVC 各分层分别为: Model (模型层)处理核心业务(数据)逻辑,模型对象负责在数据库中存取数据。这里的“数据”不仅限于数据本身,还包括处理数据的逻辑。View(视图层)用于展示数据,通常数据依据模型数据创建。Controller(控制器层)用于处理用户输入请求和响应输出,从试图读取数据,控制用户输入,并向模型发送数据。Controller 是在 Model 和 View 之间双向传递数据的中间协调者。 Spring MVC 架构及分析Spring MVC 处理一个 HTTP 请求的流程,如图所示:整个过程详细介绍:1.用户发送请求至前端控制器 DispatcherServlet。2.DispatcherServlet 收到请求调用处理器映射器 HandlerMapping。3.处理器映射器根据请求 URL 找到具体的 Controller 处理器返回给 DispatcherServlet。4.DispatcherServlet 通过处理器适配器 HandlerAdapter 调用 Controller 处理请求。5.执行 Controller 处理器的方法。6.Controller 执行完成返回 ModelAndView。7.HandlerAdapter 将 Controller 执行结果 ModelAndView 返回给 DispatcherServlet。8.DispatcherServlet 将 ModelAndView 的 ViewName 传给视图解析器 ViewReslover。9.ViewReslover 解析后返回具体的视图 View。10.DispatcherServlet 传递 Model 数据给 View,对 View 进行渲染(即将模型数据填充至视图中)。11-12.DispatcherServlet 响应用户。 ...

November 5, 2019 · 3 min · jiezi

Spring-MVC-统一响应格式源码分析以及问题解决

快速上手一般我们在写服务的时候,会有统一的返回格式,在这篇文章中用RespMsg表示。 比如根据用户的id要获取用户的信息。 第一版代码如下 @PostMapping(value = "user/{id}")public RespMsg getUserById(@PathVariable Long id) { try { return RespMsg.success(userService.getUserById(id)); } catch (BusinessException e) { log.error(e.getMessage(), e); return RespMsg.failed(e.getErrCode(), e.getMessage()); }}看了上一篇你真的了解spring boot全局异常处理吗,就可以改写为第二版 @PostMapping(value = "user/{id}")public RespMsg getUserById(@PathVariable Long id) throws BusinessException { return RespMsg.success(userService.getUserById(id));}看了这篇,就可以改写为第三版 @PostMapping(value = "user/{id}")public User getUserById(@PathVariable Long id) throws BusinessException { return userService.getUserById(id);}实现方式也很简单,通过实现ResponseBodyAdvice搭配@ControllerAdvice即可 @ControllerAdvicepublic class ResponseWrapperAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //如果已经是RespMsg类型的则直接返回 if (body instanceof RespMsg) { return body; } //如果不是,则封装 return RespMsg.success(body); }}supports方法用于判断是否支持,如果不支持则不会调用beforeBodyWrite。具体可见RequestResponseBodyAdviceChain的processBody方法。既然是统一,这里都返回true了。beforeBodyWrite方法用于改写响应。然后就大功告成了,so easy。 ...

November 3, 2019 · 2 min · jiezi

SpringMVC-Controller-返回值及异常的统一处理

旧的设计方案开发api的时候,需要先定义好接口的数据响应结果.如下是一个很简单直接的Controller实现方法及响应结果定义. @RestController@RequestMapping("/users")public class UserController { @Inject private UserService userService; @GetRequest("/{userId:\\d+}") public ResponseBean signin(@PathVariable long userId) { try { User user = userService.getUserBaseInfo(userId); return ResponseBean.success(user); } catch (ServiceException e) { return new ReponseBean(e.getCode(), e.getMsg()); } catch (Exception e) { return ResponseBean.systemError(); } }}{ code: "", data: {}, // 可以是对象或者数组 msg: ""}从上面的代码,我们可以看到对于每个 Controller 方法,都会有很多重复的代码出现,我们应该设法去避免重复的代码。将重复的代码移除之后,可以得到如下的代码,简单易懂。 @RestController@RequestMapping("/users")public class UserController { @Inject private UserService userService; @GetRequest("/{userId:\\d+}") public User signin(@PathVariable long userId) { return userService.getUserBaseInfo(userId); }}在以上的实现中,还做了一个必要的要求,就是 ServiceException 需要定义为 RuntimeException的子类,而不是 Exception的子类。由于 ServiceException 表示服务异常,一般发生这种异常是应该直接提示前端,而无需进行其他特殊处理的。在定义为 RuntimeException 的子类之后,会减少大量的异常抛出声明,而且不再需要在事务@Transactional 中进行特殊声明。 ...

November 2, 2019 · 4 min · jiezi

使用JustAuth在第三方登录中如何实现校验state

前言本文利用到的JustAuth的传送门。 本文纯属菜鸡视角。在开发者相当简略的官方使用文档的基础上,进入源码查看文档中使用的函数的具体实现,同时通过QQ第三方登录这一特例,工具开发者非常规范的命名和注释,推测整个工具的实现逻辑。 绝大部分第三方登录采用OAuth2.0协议,其流程符合如下流程图:关于OAuth2.0流程复杂化了(用户授权登录后,服务器不能直接拿到可以唯一标识用户的id)登录流程,到底在安全性上如何提供了好处,请自行谷歌。 A阶段跳转到QQ的授权登录网页必需参数 response_type client_id redirect_uri state其中response_type为一定值 B阶段用户授权登录后,腾讯那边带上必要的数据以GET参数的模型通过GET访问我们设定的返回地址。得到的数据 code state并要校验发回的state与A阶段的state是否相同 正文 准备阶段 // 官方文档中并未有此函数,只是我自用的。 private AuthQqRequest getAuthQqRequest(){ String client_id = 填入你自己的client_id; String redirect_uri = 填入你自己的redirect_url; String client_secret = 填入你自己的client_secret; AuthConfig build = AuthConfig.builder() .clientId(client_id) .clientSecret(client_secret) .redirectUri(redirect_uri) .build(); return new AuthQqRequest(build); } A阶段/** * 官方伪代码 */@RequestMapping("/render/{source}")public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException { AuthRequest authRequest = getAuthRequest(source); String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); response.sendRedirect(authorizeUrl);} /** * 我的具体到QQ上的实现 * 因为我胸无大志只想着QQ所以不需要用{source}来确定我在用谁的(是微信啊,还是QQ啊还是gitee啊)的第三方登录功能。 */ @RequestMapping("/render") public void render(HttpServletResponse resp) throws IOException { AuthQqRequest authQqRequest = getAuthQqRequest(); resp.sendRedirect(authQqRequest.authorize(AuthStateUtils.createState()); } } ...

October 16, 2019 · 3 min · jiezi

SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver

关于Web应用的全局异常处理,上一篇介绍了ControllerAdvice结合@ExceptionHandler的方式来实现web应用的全局异常管理; 本篇博文则带来另外一种并不常见的使用方式,通过实现自定义的HandlerExceptionResolver,来处理异常状态 上篇博文链接: SpringBoot系列教程web篇之全局异常处理本篇原文: SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver<!-- more --> I. 环境搭建首先得搭建一个web应用才有可能继续后续的测试,借助SpringBoot搭建一个web应用属于比较简单的活; 创建一个maven项目,pom文件如下 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7</version> <relativePath/> <!-- lookup parent from update --></parent><properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> <java.version>1.8</java.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.45</version> </dependency></dependencies><build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement></build><repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories>II. HandlerExceptionResolver1. 自定义异常处理HandlerExceptionResolver顾名思义,就是处理异常的类,接口就一个方法,出现异常之后的回调,四个参数中还携带了异常堆栈信息 @NullableModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);我们自定义异常处理类就比较简单了,实现上面的接口,然后将完整的堆栈返回给调用方 public class SelfExceptionHandler implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { String msg = GlobalExceptionHandler.getThrowableStackInfo(ex); try { response.addHeader("Content-Type", "text/html; charset=UTF-8"); response.getWriter().append("自定义异常处理!!! \n").append(msg).flush(); } catch (Exception e) { e.printStackTrace(); } return null; }}// 堆栈信息打印方法如下public static String getThrowableStackInfo(Throwable e) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); e.printStackTrace(new java.io.PrintWriter(buf, true)); String msg = buf.toString(); try { buf.close(); } catch (Exception t) { return e.getMessage(); } return msg;}仔细观察上面的代码实现,有下面几个点需要注意 ...

October 14, 2019 · 2 min · jiezi

Spring中Import的各种用法以及ImportAware接口

@Import 注解@Import注解提供了和XML中<import/>元素等价的功能,实现导入的一个或多个配置类。@Import即可以在类上使用,也可以作为元注解使用。 @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Import { /** * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar} * or regular component classes to import. */ Class<?>[] value();}注解中只有一个value();。支持导入@Configuration标注的配置类,实现ImportSelector接口的类、实现ImportBeanDefinitionRegistrar接口的类和普通的@component类。 作为元注解使用@Import可以作为元注解使用,可以在@Import的继承上封装一层。我的理解是,这样做不会对外(使用方)暴露我内部的具体实现细节。 举个例子:例如@EnableAspectJAutoProxy注解。 @Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {@EnableAspectJAutoProxy就是被@Import这个元注解所标志了,我们(程序员)通过使用@EnableAspectJAutoProxy来开启AspectJAutoProxy,而Spring底层是通过@Import导入相应的配置类来实现的。 导入实现ImportSelector接口的类先来看一下ImportSelector接口,该接口中只有一个方法: public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata);}ImportSelector,输入选择器。该接口就是用来根据给定的条件,选择导入哪些配置类。 举个例子:例如@EnableTransactionManagement注解。 @Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement {在@EnableTransactionManagement注解中使用了@Import(TransactionManagementConfigurationSelector.class)注解,其中TransactionManagementConfigurationSelector类就是实现了ImportSelector接口。 public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] { TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } }}方法的内部实现逻辑也很简单,就是根据不同的AdviceMode导入不同的配置类,来实现事务管理。 ...

October 7, 2019 · 2 min · jiezi

ControllerAdvice-使用演示

ControllerAdvice 控制器切面演示程序在spring 3.2中,新增了@ControllerAdvice 注解,并应用到所有@RequestMapping中, 可以用于定义 @ExceptionHandler 处理异常情况,根据异常类型选择处理方法;@InitBinder 数据类型转换等, 如前端请求所有参数都是字符串, 后端需要日期,则可以在此设定统一转换格式;@ModelAttribute 视图中共用的变量。@ControllerAdvice 定义了多个时,通过 @Order/@Priority 指定执行顺序。 问题1: 如何根据前端要求返回不同的数据类型,如如html 或 json?@ExceptionHandler 需要返回不同类型数据,如html 或 json, 可以通过forward:error 实现,forward:error会进入 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 里面分别有: @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections .unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); } @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity<>(body, status); }方法。但进入这个Contrller有个前提,是要设置 request.setAttribute("javax.servlet.error.status_code", 500); ...

October 7, 2019 · 5 min · jiezi

RequestBodyAdvice-和-ResponseBodyAdvice-全局处理输入输出

使用场景需要对项目中的所有输入进行前后空格的过滤替换一些特殊字符的输入解密一些关键性字段注入一些参数在请求方法的时候返回参数统一处理,如果后台返回空,统一返回成功信息身份证等特殊字符统一做 * 号处理等code主要就是用到了 RequestBodyAdvice 和 ResponseBodyAdvice 两个接口和一个注解 @ControllerAdvice 请求参数去空格package com.sanri.test.testmvc.config;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.serializer.SerializerFeature;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.IOUtils;import org.apache.commons.lang3.ObjectUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.core.MethodParameter;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpInputMessage;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Type;import java.util.Iterator;import java.util.Map;/** * 去掉前后空格和特殊字符 */@Slf4j@ControllerAdvicepublic class CustomRequestBodyAdvice implements RequestBodyAdvice { @Override public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return true; } @Override public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return body; } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException { return new CustomHttpInputMessage(httpInputMessage); } @Override public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return body; } class CustomHttpInputMessage implements HttpInputMessage{ private HttpInputMessage origin; public CustomHttpInputMessage(HttpInputMessage httpInputMessage) { this.origin = httpInputMessage; } @Override public InputStream getBody() throws IOException { HttpHeaders headers = origin.getHeaders(); InputStream body = origin.getBody(); // 空参,get 请求,流为空,非 application/json 请求,不处理参数 MediaType contentType = headers.getContentType(); if(contentType == null){return body;} if(!contentType.isCompatibleWith(MediaType.APPLICATION_JSON)){return body;} if(body == null){return body;} String params = IOUtils.toString(body, "utf-8"); if(StringUtils.isBlank(params)){return body;} // 正式过滤 json 参数 Object parse = JSON.parse(params); if (parse instanceof JSONArray) { JSONArray jsonArray = (JSONArray) parse; trimJsonArray(jsonArray); } else if (parse instanceof JSONObject) { trimJsonObject((JSONObject) parse); } else { log.error("参数不支持去空格:" + parse+ " contentType:"+contentType); } return IOUtils.toInputStream(JSON.toJSONString(parse, SerializerFeature.WriteMapNullValue), "UTF-8"); } private void trimJsonObject(JSONObject jsonObject) { Iterator<Map.Entry<String, Object>> iterator = jsonObject.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Object> next = iterator.next(); String key = next.getKey(); Object value = next.getValue(); if (value instanceof JSONArray) { trimJsonArray((JSONArray) value); }else if(value instanceof JSONObject){ trimJsonObject((JSONObject) value); }else if(value instanceof String){ String trimValue = StringUtils.trim(ObjectUtils.toString(value)); next.setValue(filterDangerString(trimValue)); } } } private void trimJsonArray(JSONArray jsonArray) { for (int i = 0; i < jsonArray.size(); i++) { Object object = jsonArray.get(i); if(object instanceof JSONObject){ JSONObject jsonObject = jsonArray.getJSONObject(i); trimJsonObject(jsonObject); }else if(object instanceof String){ String trimValue = StringUtils.trim(ObjectUtils.toString(object)); jsonArray.set(i,trimValue); } } } @Override public HttpHeaders getHeaders() { return origin.getHeaders(); } private String filterDangerString(String value) { if(StringUtils.isBlank(value))return value; value = value.replaceAll(";", ";"); value = value.replaceAll("'", "‘"); value = value.replaceAll("<", "《"); value = value.replaceAll(">", "》"); value = value.replaceAll("\\(", "("); value = value.replaceAll("\\)", ")"); value = value.replaceAll("\\?", "?"); return value; } }}使用 ResponseBodyAdvice 处理返回空返回package com.sanri.test.testmvc.config;import com.alibaba.fastjson.JSONObject;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.RestControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.lang.reflect.AnnotatedType;import java.lang.reflect.Executable;import java.lang.reflect.Type;/** * 可以定义空返回的时候返回正确的信息,如成功信息 */@RestControllerAdvicepublic class CustomResponseBodyAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { Executable executable = returnType.getExecutable(); AnnotatedType annotatedReturnType = executable.getAnnotatedReturnType(); Type type = annotatedReturnType.getType(); return JSONObject.parseObject("{\"result\":0}"); }}项目代码我弄了一个例子代码,关于 java 中每个工具的使用,如 rabbitmq,mysql,mybatis,springboot,springmvc 可以方便初学者,更方便我自己随时取用,github 地址https://gitee.com/sanri/example ...

September 8, 2019 · 2 min · jiezi

手撕面试官系列二开源框架面试题SpringSpringMVCMyBatis

跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽。切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视。 闲话不多说开始主题(面试题+答案领取方式见个人主页) 以下为常见spring面试题: 1 、什么是 Spring 框架?Spring 框架有哪些主要模块?2 、使用 Spring 框架能带来哪些好处?3 、什么是控制反转(IOC) ?什么是依赖注入?4 、请解释下 Spring 框架中的 IoC ?5 、BeanFactory 和 和 ApplicationContext 有什么区别?6 、Spring 有几种配置方式?7 、如何用基于 XML 配置的方式配置 Spring ?8 、如何用基于 Java 配置的方式配置 Spring?9 、怎样用注解的方式配置 Spring10 、请解释 Spring Bean 的生命周期?11 、Spring Bean 的作用域之间有什么区别?12 、什么是 Spring inner beans?13 、Spring 框架中的单例 Beans 是线程安全的么?14 、请举例说明如何在 Spring 中注入一个 Java Collection?15 、如何向 Spring Bean 中注入一个 Java.util.Properties ?16 、请解释 Spring Bean 的自动装配?17 、请解释自动装配模式的区别?18 、如何开启基于注解的自动装配?19 、请举例解释@Required 注解?20 、请举例解释@Autowired 注解?21 、请举例说明@Qualifier 注解?22 、构造方法注入和设值注入有什么区别?23 、Spring 框架中有哪些不同类型的事件?24 、FileSystemResource 和 和 ClassPathResource 有何区别?25 、Spring 框架中都用到了哪些设计模式? ...

July 11, 2019 · 2 min · jiezi

我对-SpringMVC-的一些误解

引言刚考完期末,再也不用考试啦!!! 最近学习了慕课网的实战课《手写SpringMVC,剑指开源框架灵魂》。 spring-boot太过智能了,智能到我们完全不用去管底层是如何实现的,都可以很轻易地去开发一款web应用。 最近将本课程和《看透Spring MVC》结合起来学习,感觉受益匪浅,同时,纠正了我之前对SpringMVC的一些误解。 误解洪荒时代的Java Web当年,开发Java Web都需要手动去实现Servlet。 public class TestServlet implements Servlet { @Override public void init(ServletConfig config) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { }}Servlet中规定了五个方法。 init初始化方法,service业务逻辑方法,destroy销毁方法。 在web.xml文件中配置路由到Servlet之间的映射,也就是说,我们没开发一个接口,都需要写一个Servlet,然后配一遍xml。 <!-- 基本配置 --><servlet> <servlet-name>test</servlet-name> <servlet-class>TestServlet</servlet-class></servlet><servlet-mapping> <servlet-name>test</servlet-name> <url-pattern>/test</url-pattern></servlet-mapping>所以就导致了项目中会有很多的Servlet,以及极其冗长的xml配置文件。 ...

July 5, 2019 · 1 min · jiezi

SpringBoot系列教程之基础篇一白话我的学习经历

有人说,Spring Boot的出现,让Java迎来了又一春,它是Java应用开发的颠覆者,彻底改变了Java应用开发的模式。2017年,SpringBoot闯入我的生活, 也让我迎来了又一春我开始接触SpringBoot的时候,是在2017年,是公司同事在开始学。我也网上查找了些资料,发现SpringBoot相比传统SpringMVC在xml配置上有很大的一部分优势:无繁琐的xml配置,各个组件依赖配置都自动加入等。我便也跟着疯狂地学起来。不得不发表一下心得体会:用起来很爽,很舒服。 学习过程,痛并快乐着我是一个天生爱折腾的主儿。喜欢学习新的技术和实现方案,挑战难点。然后把学习到的知识转化为自己的,并记录下来,整理输出。有很多也跟我一样吧。 学习springboot的时间虽过了很久,但我仍旧感觉得到当初学习SpringBoot的那股劲。 现在学习技术的途径有很多,可以看视屏教程,看博客,看码云和Github都可以呢。 学习过程中,我也总是会遇到各种问题,或者不明白的知识点,也就是知识盲区,我会怎么做呢?根据这个知识点,提炼出“关键字”去百度或者谷歌搜索,对知识点先有一个大体的了解。但是要从浩瀚的资料中,筛选出有用的资料,那还真得有一双敏感的慧眼吧。我在搜索资料的时候,心里面就会去评估这份资料: 第一层:看到不符合的,直接pass掉。第二层:比较符合的。收集下来,再寻找相似的,方便后面做对比。第三层:直接符合的。那就是实践。看是否能正确解决。并做好记录。不断试错是一种态度。也正是这样的思考方式,解决了我遇到的很多问题。 在学习SpringBoot的过程中,除了基础知识点的积累,我少不了去找许多开源项目案例研究学习,折腾各种环境部署,并从中找到我需要的那部分,然后运用到自己的项目中。我很感谢有前辈们的探索和分享。 我当时的目标很简单,就一个----学好SpringBoot,然后能成功整合各个项目,并简单的用起来。 只是学会用的话,如果有SpringMVC的使用经验的话,上手是分分钟的。 当时,我的目的也很单纯,就是学会用,其他也没多想。我开始简单地搭建了三层架构,然后慢慢开始整合相关组件,实现功能需求。 就这么简单的目的,我什么都不想去实现它就可以了。然而会有很多人,还没开始去做,就开始打退堂鼓。从心里面就已经告知自己:“我不会,我不行,没有大佬带。”,就这样,每天活在痛苦和焦虑中。 有些路必须得自己去走,才能知道沿途的风景是多么的迷人。我曾经也很想会有大佬带,学什么会什么。但对于我们这样的无名小卒,菜鸟小白,谁又会去关心呢。只能啃书,啃视频。有问题也不知道该如何解决。 痛苦在所难免,但如果有我陪着,你是否不会感觉到孤单。我是一天不写代码就剁手的程序猿。遇到的问题,也尽可能的去一起解决,减轻学习上的痛苦。 我当时大概学习了一两周,就开始上手,整合项目,直接开干。在项目中去夯实基础。 学习完了,就得实战。不说了,直接干它一个商城!其过程可谓是艰辛痛苦,那可谓是网上搜罗各种资料博客,github上找Demo项目学习,也算是很艰辛的一段学习历程。 我在的公司是个小公司,但我当时主要负责聚合支付类项目的开发,一想到互联网的项目,应该使用的是比较新的技术开发,终于可以涨姿势了。当时就我一个人接手,我还很高兴,终于能挺起腰杆,撸起袖子,大干一场。但当我真正去接手的时候,我不敢相信自己的眼睛,项目是用servlet+jsp实现,还是几个研究生实习开发的。现在都二十一世纪了好吧,还是互联网项目。咋就没看出一点互联网项目的气息。 收了,吐槽结束。 也许正因为是在这样的环境下,让我有机会去把所学的给施展开来。当时,我一边用原来的技术开发着原有的功能,一边在谋划用SpringBoot新框架的搭建和实现。 我很喜欢当时带我项目的老师说的一句话:用你最熟悉的语言开发。 我深信不疑。 后来,整个的搭建思路,前后端的整合过程,百分之90是我独立完成的。我也很成功的将原有的旧项目V1.0,迁移到我新搭建的SpringBoot项目中,并按照规范开发,就基本上完成SpringBoot单体应用V2.0整合。后面,由于有其他需求,又进行了SpringBoot+Dubbo的微服务搭建V3.0。 正因为有了这样的经历,我知道这样的经验很宝贵,也很来之不易。当然也有我很多没有考虑到的,还需继续学习。 遗憾的是,当初没有做好笔记,光顾着自己爽了。现在也只能靠着自己残缺的记忆。 不遗憾的是,我依然还有心去做一件我值得去做的事----那就是将零散的知识点,躺过的坑,能总结分享,有机地形成一个个系列。 这也是我现在准备去做的事情。 曾经的我也开始过,但后来没有写下去,因为自己的口才和知识面不够,没有多少的落地经验,自然也写不出,即使写得出,也写不好,写不清楚。 相比之前的我,现在的我,年岁长了,经验长了,学到的和看到的多了。也写了几万的文字。也更有底气去做这件事情,相信可以写得更好。 于你,可以跟我一起,学习SpringBoot,并能真正的从基础入门到独自搭建属于自己的框架,为自己增添技术实力, 而且掌握大小公司里的开发技巧,工作习惯。 于我,可以在写教程中,反思自我,争取做得更好。也可能会有更好,更有趣的想法在其中产生。

June 18, 2019 · 1 min · jiezi

Spring-里那么多种-CORS-的配置方式到底有什么区别

作为一个后端开发,我们经常遇到的一个问题就是需要配置 CORS,好让我们的前端能够访问到我们的 API,并且不让其他人访问。而在 Spring 中,我们见过很多种 CORS 的配置,很多资料都只是告诉我们可以这样配置、可以那样配置,但是这些配置有什么区别? CORS 是什么首先我们要明确,CORS 是什么,以及规范是如何要求的。这里只是梳理一下流程,具体的规范请看 这里。 CORS 全称是 Cross-Origin Resource Sharing,直译过来就是跨域资源共享。要理解这个概念就需要知道域、资源和同源策略这三个概念。 域,指的是一个站点,由 protocal、host 和 port 三部分组成,其中 host 可以是域名,也可以是 ip ;port 如果没有指明,则是使用 protocal 的默认端口资源,是指一个 URL 对应的内容,可以是一张图片、一种字体、一段 HTML 代码、一份 JSON 数据等等任何形式的任何内容同源策略,指的是为了防止 XSS,浏览器、客户端应该仅请求与当前页面来自同一个域的资源,请求其他域的资源需要通过验证。了解了这三个概念,我们就能理解为什么有 CORS 规范了:从站点 A 请求站点 B 的资源的时候,由于浏览器的同源策略的影响,这样的跨域请求将被禁止发送;为了让跨域请求能够正常发送,我们需要一套机制在不破坏同源策略的安全性的情况下、允许跨域请求正常发送,这样的机制就是 CORS。 预检请求在 CORS 中,定义了一种预检请求,即 preflight request,当实际请求不是一个 简单请求 时,会发起一次预检请求。预检请求是针对实际请求的 URL 发起一次 OPTIONS 请求,并带上下面三个 headers : Origin:值为当前页面所在的域,用于告诉服务器当前请求的域。如果没有这个 header,服务器将不会进行 CORS 验证。Access-Control-Request-Method:值为实际请求将会使用的方法Access-Control-Request-Headers:值为实际请求将会使用的 header 集合如果服务器端 CORS 验证失败,则会返回客户端错误,即 4xx 的状态码。 否则,将会请求成功,返回 200 的状态码,并带上下面这些 headers: ...

June 15, 2019 · 6 min · jiezi

java中RedirectAttributes类的使用

一、RedirectAttributes类简介RedirectAttributes是Spring mvc 3.1版本之后出来的一个功能,专门用于重定向之后还能带参数跳转的工具类使用此类引入包:import org.springframework.web.servlet.mvc.support.RedirectAttributes;划重点:用于重定向携带参数二、类中常用方法介绍addAttributie方法 redirectAttributes.addAttributie("param1",value1); redirectAttributes.addAttributie("param2",value2); return "redirect:/path/list" ;注意:这个方法是用来跳转的时候,将参数直接暴露在url中,等同于重定向到:return "redirect:/path/list?prama1=value1&param2=value2 " addFlashAttributie方法 redirectAttributes.addFlashAttributie("prama1",value1); redirectAttributes.addFlashAttributie("prama2",value2);

June 14, 2019 · 1 min · jiezi

聊聊Spring-MVC中-handlerMapping和handlerAdapter设计思想

先上一段Spring MVC核心类DispatcherServlet中最重要的方法doDispatch源码 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 根据当前请求获取对应的处理器映射器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // 根据handler类型获取对应的处理器适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }}关注代码中打中文注释的两个地方,一个获取对应handler的处理器映射器,一个获取对应handler的处理器适配器。那为什么需要这两个东西,我们直接在handler中写映射逻辑,直接通过handler来执行处理器方法难道不行吗?答案是否定的,但Spring为什么要这样做?有以下几个好处 ...

June 6, 2019 · 2 min · jiezi

Spring-MVC-文件流形式下载返回视频文件

import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;/** * 文件流形式下载视频 * @author Front Ng * @date 2019-05-23 09:25 **/@Controller@RequestMapping(value = "/download")@Api(value = "下载", tags = "下载")public class DownloadController { @ApiOperation(value = "下载视频") @RequestMapping(method = RequestMethod.GET) public void download(HttpServletResponse response) throws IOException { File file = new File("/Users/front/Downloads/123.mp4"); FileInputStream inputStream = new FileInputStream(file); byte[] data = new byte[(int) file.length()]; int length = inputStream.read(data); inputStream.close(); String fileName = URLEncoder.encode("文件流形式视频.mp4", "UTF-8"); response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); response.addHeader("Content-Length", "" + data.length); OutputStream stream = response.getOutputStream(); stream.write(data); stream.flush(); stream.close(); }}

May 23, 2019 · 1 min · jiezi

FastDFS-Docker化部署-以及-Java-SpringMVC实践

简介FastDFS是一个轻量级分布式文件系统。可以对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,而且可以集群部署,有高可用保障。相应的竞品有Ceph、TFS等。相比而言FastDFS对硬件的要求比较低,所以适合中小型公司。 概念FastDFS服务端由两个重要部分组成:跟踪器(Tracker)和存储节点(Storage)。 Tracker主要做调度工作,在访问上起负载均衡的作用。Tracker可以做集群部署,各个节点之间是平等的,客户端请求时采用轮询机制,某个Tracker不能提供服务时就换另一个。Storage启动后会连接到Tracker Server告知自己的Group信息,形成映射关联,并采用心跳机制保持状态。Storage存储节点负责文件的存储,Storage可以集群部署。 Storage集群有以下特点: 以组(Group)为单位(也有称呼为卷 Volume的),集群的总容量为所有组的集合。一个卷(组)内storage server之间相互通信,文件进行同步,保证卷内storage完全一致,所以一个卷的容量以最小的服务器为准。不同的卷之间相互不通信。当某个卷的压力较大时可以添加storage server(纵向扩展),如果系统容量不够可以添加卷(横向扩展)。上传流程此章节根据资料整理,可能随着版本有所改变,这里只介绍大致的,以便了解整个运作流程。如果需要深入研究,建议还是以官方文档为标准。 一,客户端请求会打到负载均衡层,到tracker server时,由于每个server之间是对等的关系,所以可以任意选择一个tracker server。 二,到storage层:tracker server接收到upload file请求时,会为该请求分配一个可以存储该文件的group。 分配group规则: Round robin 轮询Specified group 指定一个groupLoad balance 剩余存储空间多的group优先三,确定group后,tracker会在group内选择一个storage server给客户端。 在group内选择storage server时规则: Round robin 轮询First server ordered by ip 按ip排序First server ordered by priority,按优先级排序(优先级在storage上配置)四,选择storage path:当分配好storage server后,客户端向storage发送写文件请求,storage将会为文件分配一个数据存储目录,支持规则如下: round robin 轮询剩余存储空间最多的优先五,生成File id:选定存储目录之后,storage会为文件生成一个File id。规则如下: 由storage server ip、文件创建时间、文件大小,文件crc32和一个随机数拼接而成,然后将这个二进制串进程base64编码,转换为可打印的字符串。六,选择两级目录:每个存储目录下有两级256 * 256的子目录,storage会按文件Field进行两次hash,路由到其中的一个目录,然后将文件以file id为文件名存储到该子目录下。 一个文件路径最终由如下组成:组名/磁盘/目录/文件名 七,客户端upload file成功后,会拿到一个storage生成的文件名,接下来客户端根据这个文件名即可访问到该文件。 下载流程下载流程如下: 一,选择tracker server:和upload file一样,在download file时随机选择tracker server。 二,选择group:tracker发送download请求给某个tracker,必须带上文件名信息,tracker从文件名中解析出group、大小、创建时间等信息,根据group信息获取对于的group。 三,选择storage server:从group中选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到的时候,文件还没有同步到某些storage server上,为了尽量避免反问道这样的storage,tracker按照一定的规则选择group内可读的storage。 文件HTTP预览服务Storage还可以结合nginx的fastdfs-nginx-module提供http服务,以实现图片等预览功能。 这个部分这里不做介绍,后续可能单独写篇文章,因为我发现对fastDFS集群提供http服务还是挺复杂,包括我下面找的docker镜像都不完善,主要是规划的问题,包括衍生的服务,缓存,以及对图片的处理(nginx+lua)这些,后续打算研究下,重新开源个docker构建镜像。 ...

May 23, 2019 · 2 min · jiezi

从零入门系列4Sprint-Boot-之-WEB接口设计实现

文章系列【从零入门系列-0】Sprint Boot 之 Hello World【从零入门系列-1】Sprint Boot 之 程序结构设计说明【从零入门系列-2】Sprint Boot 之 数据库实体类【从零入门系列-3】Sprint Boot 之 数据库操作类)前言前一章简述了已经实现了对数据库的增删改查以及复杂查询的功能,这一步将对相应的功能方法封装成WEB接口,对外提供WEB接口服务。 控制层类设计及测试控制层的角色是负责对访问路由到处理过程的关联映射和封装,在这里我们队Book新建一个控制类即可,在文件夹Controller上右键,New->Java Class新建BookController类。作为控制类,该类需要使用@Controller注解使之能够被识别为控制类对象,在这里我们使用@RestController,该注解包含了@Controller,相当于@Controller+@ResponseBody两个注解的结合,适合返回Json格式的控制器使用。 类定义@RestController@RequestMapping(path = "/library")public class BookController { @Autowired private BookJpaRepository bookJpaRepository; @Autowired private BookService bookService;}考虑到数据库的操作需要用到BookJpaRepository和BookService,这里首先声明这两个属性,并使用@Autowired注解自动装配。 在类上使用@RequestMapping(path = "/library")注解后,定义了该类的路径都是/library开始,可以统一接口路径,避免重复书写。 新增接口/*** 新增书籍* @param name* @param author* @param image* @return*/@PostMapping("/save")public Map<String, Object> save(@RequestParam String name, @RequestParam String author, @RequestParam String image){ Book book = new Book(); Map<String, Object> rsp = new HashMap<>(); book.setName(name); book.setAuthor(author); book.setImage(image); bookJpaRepository.save(book); rsp.put("data", book); rsp.put("code", "0"); rsp.put("info", "成功"); return rsp;}使用@PostMapping表示接口只接受POST请求,WEB接口路径为/library/save,该接口返回的是一个Map类型对象,但是由于类使用@RestController注解后,使得返回结果会自动转换成Json字符串格式。 ...

May 15, 2019 · 4 min · jiezi

SpringMVC框架入门

简介SpringMVC采用模型(Model)-视图(View)-控制器(controller)的方法把业务逻辑、数据与界面显示分离。用通俗的话来讲,MVC的理念就是把数据处理、数据展示和程序/用户的交互三者分离开的一种编程模式。 为什么要学SpringMVC? SpringMVC相比Struts2要更为简单,便捷,容易学,性能也要比Struts2好。天生与Spring框架集成(如IoC容器、AOP等)提供强大的约定大于配置的契约式编程支持能够进行简单的junit测试支持restful风格更加简单的异常处理非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的API使用人数多,使用的公司多等等SpringMVC简单运行过程 更多免费精品课程:阿里云大学—开发者课堂

May 10, 2019 · 1 min · jiezi

SpringMVC方法四种类型返回值总结你用过几种

SpringMVC 现在算是 Java 领域的一个基础性框架了,很多人天天用,可是对于 SpringMVC 方法的返回值,你又是否完全清楚呢?今天松哥就来和大家聊一聊 SpringMVC 中四种不同类型的返回值,看看有没有 get 到你的知识盲点? 1. ModelAndView以前前后端不分的情况下,ModelAndView 应该是最最常见的返回值类型了,现在前后端分离后,后端都是以返回 JSON 数据为主了。后端返回 ModelAndView 这个比较容易理解,开发者可以在 ModelAndView 对象中指定视图名称,然后也可以绑定数据,像下面这样: @RequestMapping("/book")public ModelAndView getAllBook() { ModelAndView mv = new ModelAndView(); List<Book> books = new ArrayList<>(); Book b1 = new Book(); b1.setId(1); b1.setName("三国演义"); b1.setAuthor("罗贯中"); books.add(b1); Book b2 = new Book(); b2.setId(2); b2.setName("红楼梦"); b2.setAuthor("曹雪芹"); books.add(b2); //指定数据模型 mv.addObject("bs", books); mv.setViewName("book");//指定视图名 return mv;}返回 ModelAndView ,最常见的两个操作就是指定数据模型+指定视图名 。 2. Void返回值为 void 时,可能是你真的没有值要返回,也可能是你有其他办法,松哥将之归为如下四类,大伙来看下。 2.1 没有值如果确实没有返回值,那就返回 void ,但是一定要注意,此时,方法上需要添加 @ResponseBody 注解,像下面这样: ...

May 6, 2019 · 2 min · jiezi

从零开始搭建SSM框架Spring-Spring-MVC-Mybatis

最近在回顾和总结一些技术,想到了把之前比较火的 SSM 框架重新搭建出来,作为一个小结,同时也希望本文章写出来能对大家有一些帮助和启发,因本人水平有限,难免可能会有一些不对之处,欢迎各位大神拍砖指教,共同进步。 本文章示例使用 IntelliJ IDEA 来开发,JDK 使用 11 版本,其余各框架和技术基本上使用了文章撰写当时的最新版本。 好的,下面直接进入正题。 打开 IntelliJ IDEA,File > New > Project > Maven,选中“Create from archetype”,然后再选中“org.apache.maven.archetypes:maven-archetype-webapp”: Next,输入项目的“GroupId”、“ArtifactId”和Version: Next,指定“Maven home directory”等配置: Next,修改Project Name: Finish,打开项目,添加一些必要的目录,最终项目框架目录图如下: 修改pom.xml文件,指定各依赖和插件的版本等信息: <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>11</java.version> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <spring.version>5.1.6.RELEASE</spring.version> <junit.version>4.12</junit.version> <lombok.version>1.18.6</lombok.version> <mybatis-plus.version>3.1.1</mybatis-plus.version> <freemarker.version>2.3.28</freemarker.version> <druid.version>1.1.16</druid.version> <jsqlparser.version>2.0</jsqlparser.version> <mysql-connector.version>8.0.16</mysql-connector.version> <jstl-api.version>1.2</jstl-api.version> <servlet-api.version>4.0.1</servlet-api.version> <jsp-api.version>2.3.3</jsp-api.version> <springfox-swagger.version>2.9.2</springfox-swagger.version> <commons-lang3.version>3.9</commons-lang3.version> <jackson.version>2.9.8</jackson.version> <mapstruct.version>1.3.0.Final</mapstruct.version> <log4j.version>2.11.2</log4j.version> <slf4j.version>1.7.26</slf4j.version> <clean.plugin.version>3.1.0</clean.plugin.version> <resources.plugin.version>3.1.0</resources.plugin.version> <compiler.plugin.version>3.8.0</compiler.plugin.version> <surefire.plugin.version>3.0.0-M3</surefire.plugin.version> <war.plugin.version>3.2.2</war.plugin.version> <install.plugin.version>3.0.0-M1</install.plugin.version> <deploy.plugin.version>3.0.0-M1</deploy.plugin.version></properties>在<dependencyManagement>标签里面管理各依赖的版本号: <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${mybatis-plus.version}</version> <scope>test</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>${freemarker.version}</version> <scope>test</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>${jsqlparser.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>${jstl-api.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox-swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox-swagger.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> </dependency> </dependencies></dependencyManagement>添加项目依赖: ...

May 3, 2019 · 8 min · jiezi

第二讲SpringSpring-MVCSpring-Boot三者之间的区别与联系

Spring Framework的诞生让开发人员的工作从石器时代跨域到了工业时代,你是否还能记起手撸Servlet和JDBC的岁月?,你是否还对Struts1以及Struts2莫名其妙的404错误记忆犹新?从2004年3月Spring 1.0发布到至今,Spring的发展已经走过了15个年头,其创造的价值让人瞩目。今天,带着这样一个背景来梳理一下Spring Framework,Spring MVC和Spring Boot三者之间的区别。 我们使用Spring家族的系列产品这么长时间,不禁会问这样几个问题:Spring Framework是什么?Spring MVC是什么?Spring Boot又是什么?它们被设计出来的目的是什么? 你需要了解的知识在接下来的内容中,将梳理这样几个知识点: Spring Framework基本概述Spring Framework主要解决的问题是什么?Spring MVC基本概述Spring MVC主要解决的问题是什么?Spring Boot主要解决的问题是什么?Spring,Spring MVC和Spring Boot三者之间的区别是什么?Spring Framework 解决了哪些核心问题?当你仔细思考这个问题的时候你会发现,很多地方它都有渗透到,貌似一个Spring就可以撑起开发的半边天,以至于很难一下子回答这个问题。那Spring Framework到底解决了哪些核心问题? Spring Framework最重要也是最核心的特性是依赖注入。所有的Spring模块的核心就是DI(依赖注入)或者IoC(控制反转)。依赖注入或控制反转是Spring Framework最大的特性,当我们正确使用DI(依赖注入)或IoC时,可以开发出一个高内聚低耦合的应用程序,而这一一个低耦合的应用程序可以轻松的对其实施单元测试。这就是Spring Framework解决的最核心的问题。 无依赖注入请考虑这一一个案例:UserAction依赖于UserService来获取用户信息,在没有依赖注入的情况下,我们需要手动在UserAction中实例化一个UserService对象,这样的手工作业意味着UserAction和UserService必须精密的联系在一起,才能正常工作。如果一个Action需要多个Service提供服务,那实例化这些Service将是一个繁重的工作。下面我们给出一个不使用依赖注入的代码片段加以说明: UserService.java public interface UserService{ User profile();}UserServiceImpl.java public class UserServiceImpl implements UserService{ @Override User profile(){ // TODO }}UserAction.java @RestControllerpublic class UserAction{ private UserService userService = new UserServiceImpl(); // other services... @GetMapping("/profile") public User profile(){ return userService.profile(); }}引入依赖注入引入依赖注入将会使整个代码看起来很清爽。为了能够开发出高内聚低耦合的应用程序,Spring Framework为我们做了大量的准备工作。下面我们使用两个简单的注解@Component和@Autowired来实现依赖注入。 @Component : 该注解将会告诉Spring Framework,被此注解标注的类需要纳入到Bean管理器中。@Autowired : 告诉Spring Framework需要找到一与其类型匹配的对象,并将其自动引入到所需要的类中。在接下来的示例代码中,我们会看到Spring Framework将为UserService创建一个Bean对象,并将其自动引入到UserAction中。 ...

April 24, 2019 · 2 min · jiezi

SpringMVC 中 @ControllerAdvice 注解的三种使用场景!

@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能: 全局异常处理全局数据绑定全局数据预处理灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,下面分别来看。 全局异常处理使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下: @ControllerAdvicepublic class MyGlobalExceptionHandler { @ExceptionHandler(Exception.class) public ModelAndView customException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("message", e.getMessage()); mv.setViewName("myerror"); return mv; }}在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法...,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。 @ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。 全局数据绑定全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能够访问导致这些数据。 使用步骤,首先定义全局数据,如下: @ControllerAdvicepublic class MyGlobalExceptionHandler { @ModelAttribute(name = "md") public Map<String,Object> mydata() { HashMap<String, Object> map = new HashMap<>(); map.put("age", 99); map.put("gender", "男"); return map; }}使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key。 ...

April 22, 2019 · 1 min · jiezi

spring boot学习(7)— 自定义中的 HttpMessageConverter

在我们开发自己的应用时,有时候,我们可能需要自定义一些自己的数据格式来传输,这时,自定义的数据传输和类的实例之间进行转化就需要统一起来了, Spring MVC 中的 HttpMessageConverter 就派上用场了。 HttpMessageConverter 的声明:public interface HttpMessageConverter<T> { /** * Indicates whether the given class can be read by this converter. * @param clazz the class to test for readability * @param mediaType the media type to read (can be {@code null} if not specified); * typically the value of a {@code Content-Type} header. * @return {@code true} if readable; {@code false} otherwise */ boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); /** * Indicates whether the given class can be written by this converter. * @param clazz the class to test for writability * @param mediaType the media type to write (can be {@code null} if not specified); * typically the value of an {@code Accept} header. * @return {@code true} if writable; {@code false} otherwise */ boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); /** * Return the list of {@link MediaType} objects supported by this converter. * @return the list of supported media types */ List<MediaType> getSupportedMediaTypes(); /** * Read an object of the given type from the given input message, and returns it. * @param clazz the type of object to return. This type must have previously been passed to the * {@link #canRead canRead} method of this interface, which must have returned {@code true}. * @param inputMessage the HTTP input message to read from * @return the converted object * @throws IOException in case of I/O errors * @throws HttpMessageNotReadableException in case of conversion errors */ T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; /** * Write an given object to the given output message. * @param t the object to write to the output message. The type of this object must have previously been * passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}. * @param contentType the content type to use when writing. May be {@code null} to indicate that the * default content type of the converter must be used. If not {@code null}, this media type must have * previously been passed to the {@link #canWrite canWrite} method of this interface, which must have * returned {@code true}. * @param outputMessage the message to write to * @throws IOException in case of I/O errors * @throws HttpMessageNotWritableException in case of conversion errors */ void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;}里面有四个方法: ...

April 21, 2019 · 3 min · jiezi

使用maven创建简单的多模块 Spring Web项目

第一次写技术文章,主要内容是使用maven创建一个简单的SpringMVC WEB 项目,如有操作或理解错误请务必指出,当谦虚学习。做这一次的工作主要是因为想加强一下自己对Spring Web 项目的理解,因为平时都是直接写业务代码,我觉得还是有必要自己了解一下创建项目的过程。后续会基于这个项目写更多的SpringWeb开发过程,希望能帮助到有需要的人。总的来说是一个相当精简的多模块springWeb项目搭建过程,让我们进入正题吧我们知道单体应用,就写在一个project里面的话,业务一旦庞大起来非常难以管理。把各个模块单独抽出来可以方便的对jar包进行版本管理(尽管我还没经历过这个),维护项目,团队开发也会方便许多。基本思想其实就是一个java web项目引用别的模块Jar包,最终web项目被打成war包发布。而所有的war包项目,jar包项目都是在同一个父模块下管理的(它们都是Maven项目)(如果你有IDE,装好插件就用IDE创建吧,我个人不喜欢手动命令行创建)1. 创建父项目下图中:框起来打勾这个会让你跳过项目模式选择,勾选对于创建项目没有什么影响,以后也许会转一下Maven这方面的文章POM包才能做父项目,谨记!!!!! 2. 子项目结构和创建以下是我的结构分层,你也可以按你的想法来,最终目的是要方便自己开发。test_parent (父项目) |—-test_web (web项目) |—-test_service (业务内容) |—-test_framework (工具,框架封装、配置) |—-test_dao (数据持久层,DO也放这) |—-test_controller (处理映射) 创建子项目直接右键父项目然后新建maven module ,也就是子模块我们先创建web模块,这里你可以勾选第一条然后创建简单项目,如果没有勾选,那么你要在下一步里选择 maven-achetype-webapp,这里以简单项目为例子Group Id 和 version 都是继承父项目的一定要选择war包打包,不然要重新把他构建成web项目。如果你没选war包:https://www.cnblogs.com/leonk…最后点finish完成点击生成Web描述文件 (web.xml)这样就完成了Web模块的创建,剩下的其他项目都是同样的步骤创建,都是选择jar包,参考下图:3. 配置各模块的pom.xmlpom.xml记录所需的jar包,模块联系,包信息,打包参数等等信息,在多模块里我们要理清关系,不要重复引用首先毫无疑问的是让parent加载spring的jar包是最方便开发的,因为默认所有模块都继承parent,所以子模块引用spring内容也方便。其次配置文件我们统一放在framework中进行管理。那么先来写入web.xml配置吧<?xml version=“1.0” encoding=“UTF-8”?><web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://java.sun.com/xml/ns/javaee" xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id=“WebApp_ID” version=“3.0”> <display-name>test_web</display-name> <context-param> <!– 配置地址 –> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!– spring-mvc.xml 配置地址 –> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/</url-pattern> </filter-mapping></web-app>这里可以看到我们写了classpath,原因是它能搜索到项目目录以外的Jar包下文件相关:http://www.cnblogs.com/wlgqo/…web.xml详解:https://blog.csdn.net/qq_3557…web.xml是对WEB项目来说是必须的配置文件,写好了spring配置文件的位置以后,就来新建2个spring配置文件,新建的配置放在test_framework模块里,路径如下图 spring-context.xml spring-mvc.xml一个是spring-context.xml 也叫applicationContext.xml,是webApp的上下文配置,也可以理解为配置dao、service 通用bean的地方,但我们这里使用的是注解扫描方式配置bean,所以就简单许多,即便有工具存在,写改xml真的很讨厌啊!<?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:mvc=“http://www.springframework.org/schema/mvc" xmlns:context=“http://www.springframework.org/schema/context" xmlns:tx=“http://www.springframework.org/schema/tx" xmlns:util=“http://www.springframework.org/schema/util" xmlns:aop=“http://www.springframework.org/schema/aop" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!– 注解注册 –> <!– <context:annotation-config /> –> <context:component-scan base-package=“com.test” > <context:exclude-filter type=“annotation” expression=“org.springframework.stereotype.Controller” /> <context:exclude-filter type=“annotation” expression=“org.springframework.web.bind.annotation.RestController” /> </context:component-scan> </beans>这里要去掉对controller的扫描,applicationContext初始化的上下文加载的Bean是对于整个应用程序共享的,不管是使用什么表现层技术,一般如DAO层、Service层Bean; DispatcherServlet (下一个要配置的东西) 初始化的上下文加载的Bean是只对Spring Web MVC有效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文应该只加载Web相关组件。context:component-scan 的 base-package 值用来决定我们需要扫描的包的基础名,具体配置相关可以看:https://www.cnblogs.com/exe19…而context:annotation-config/ 呢?其实也是spring为了方便我们开发者给我们提供的一个自动识别注解的配置,相关细节如下:解释说明:https://www.cnblogs.com/_popc…两条配置的区别和诠释:https://www.cnblogs.com/leiOO…下面是第二个配置文件 spring-mvc.xml<?xml version=“1.0” encoding=“UTF-8” standalone=“no”?><beans xmlns=“http://www.springframework.org/schema/beans" xmlns:context=“http://www.springframework.org/schema/context" xmlns:aop=“http://www.springframework.org/schema/aop" xmlns:mvc=“http://www.springframework.org/schema/mvc" xmlns:p=“http://www.springframework.org/schema/p" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!– 自动扫描的包名 –> <context:component-scan base-package=“com.test.*.controller” > <context:include-filter type=“annotation” expression=“org.springframework.stereotype.Controller” /> </context:component-scan> <!– 默认的注解映射的支持 –> <mvc:annotation-driven> <mvc:message-converters> <bean class=“org.springframework.http.converter.StringHttpMessageConverter”> <constructor-arg value=“UTF-8” /> </bean> <bean class=“org.springframework.http.converter.ResourceHttpMessageConverter” /> </mvc:message-converters> </mvc:annotation-driven></beans>包扫描没什么好说的,这里还强调include了注解controller。mvc:annotation-driven 是spring默认的注解驱动,这个配置项一口气把一堆东西都给我们加进来了,但主要还是针对controller和处理请求的,具体的在下面文章中,因为加的内容有点多,所以这个留到后面研究,稍微理解作用就好:相关文章 : https://blog.csdn.net/vicroad...mvc:message-converters 顾名思义,就是用于处理请求消息的,request content-header 会记录请求的内容类型,根据这些类型,spring会把内容转化成服务器操作的对象,这里的字符串转化是为了避免乱码,我们指定了编码格式。相关文章:https://www.jianshu.com/p/2f6…以上,我们就已经把最简约的配置写好了。接下来我们随便写一个controller试试4.写个Controller吧根据之前写好的controller的扫描包名,去我们test_controller模块里创建一个controllerpackage com.test.hello.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test”)public class HelloController{ @RequestMapping("/get”) public String helloGet(@RequestParam String str) throws Exception { return str; }}很简单的一段返回请求字符串的代码,现在一切就绪可以启动服务器了,配置好Tomcat就可以启动了,右键test_web –> run as –> run on server 选择创建好的tomcat容器,就可以启动了。接下来,访问: localhost:8080/test/test/get?str=helloWorld 如果你使用eclipse启动且没有正常启动,特别是出现严重错误时,请先检查web.xml配置命名有没有问题,然后再检查test_web项目的assembly,这个会影响项目的发布文件,下图所示,右键项目点properties,没有test_framework的话就加入framework项目。网站无响应,检查一下tomcat的端口,默认是8080。404检查代码的映射路径。5.结束语第一次写技术文章,记录一下自己的学习过程,日后会以当前项目作为基础,继续记录下自己遇到的问题和分享的知识,希望能帮助到一部分新手,此外,本篇文章中若有错误,欢迎指出,我会不断更新文章误点,不吝赐教。 ...

April 4, 2019 · 2 min · jiezi

扩展spring cache 支持缓存多租户及其自动过期

spring cache 的概念Spring 支持基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。@Cacheable 使用效果 ,更具 cacheName(value) + 请求入参 (key) 组成保存redis中的keypublic class PigxClientDetailsService extends JdbcClientDetailsService { @Cacheable(value = SecurityConstants.CLIENT_DETAILS_KEY, key = “#clientId”) public ClientDetails loadClientByClientId(String clientId) { return super.loadClientByClientId(clientId); }}}多租户下缓存问题分析默认情况 A租户入参为K1 请求 应用,spring cache 会自动缓存 K1 的值,如果B租户 入参同时为K1 请求应用时,spring cache 还是会自动关联到同一个 Redis K1 上边查询数据。在多租户下 A/B 租户所请求的K1 并不是同一入参(虽然看起来参数名 参数值都是一样的),更不能返回同一个结果。默认的spring cache 根据入参来区分 不能满足多租户系统的设计需求,不能实现根据租户隔离。区分缓存增加租户标识A租户入参为K1 ,spring cache 维护Redis Key 在拼接一个租户信息KEY = cacheName + 入参 + 租户标识这样A/B 租户请求参数相同时,读取的也是不同的Key 里面的值,避免数据脏读,保证隔离型重写Spring Cache 的 cacheManager 缓存管理器从上下文中获取租户ID,重写@Cacheable value 值即可完成,然后注入这个 cacheManager@Slf4jpublic class RedisAutoCacheManager extends RedisCacheManager { /** * 从上下文中获取租户ID,重写@Cacheable value 值 * @param name * @return */ @Override public Cache getCache(String name) { return super.getCache(TenantContextHolder.getTenantId() + StrUtil.COLON + name); }}为什么要用 StrUtil.COLON 即 ‘:’ 分割在GUI 工具中,会通过’:‘的分隔符,进行分组,展示效果会更好增加 spring cache 的主动过期功能默认的注解里面没有关于时间的入参,如下图public @interface Cacheable { @AliasFor(“cacheNames”) String[] value() default {}; @AliasFor(“value”) String[] cacheNames() default {}; String key() default “”; String keyGenerator() default “”; String cacheManager() default “”; String cacheResolver() default “”; String condition() default “”; String unless() default “”; boolean sync() default false;}还是以value作为入口 value = “menu_details#2000” 通过对vaue 追加一个数字 并通过特殊字符分割,作为过期时间入参@Service@AllArgsConstructorpublic class PigXMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService { private final SysRoleMenuMapper sysRoleMenuMapper; @Override @Cacheable(value = “menu_details#2000”, key = “#roleId + ‘_menu’”) public List<MenuVO> findMenuByRoleId(Integer roleId) { return baseMapper.listMenusByRoleId(roleId); }}重写cachemanager 另个重要的方法 创建缓存的方法,通过截取 value 中设置的过期时间,赋值给你RedisCacheConfigurationpublic class RedisAutoCacheManager extends RedisCacheManager { private static final String SPLIT_FLAG = “#”; private static final int CACHE_LENGTH = 2; @Override protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) { if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) { return super.createRedisCache(name, cacheConfig); } String[] cacheArray = name.split(SPLIT_FLAG); if (cacheArray.length < CACHE_LENGTH) { return super.createRedisCache(name, cacheConfig); } if (cacheConfig != null) { long cacheAge = Long.parseLong(cacheArray[1]); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(cacheAge)); } return super.createRedisCache(name, cacheConfig); }}spring cache 操作缓存时 获取到上步设置的ttl 赋值给key @Override public void put(Object key, @Nullable Object value) { Object cacheValue = preProcessCacheValue(value); if (!isAllowNullValues() && cacheValue == null) { throw new IllegalArgumentException(String.format( “Cache ‘%s’ does not allow ’null’ values. Avoid storing null via ‘@Cacheable(unless="#result == null")’ or configure RedisCache to allow ’null’ via RedisCacheConfiguration.”, name)); } cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl()); }总结通过对spring cache 的扩展即可实现对缓存 一些透明操作cachemanager 是springcache 对外提供的API 扩展入口以上源码参考个人项目 基于Spring Cloud、OAuth2.0开发基于Vue前后分离的开发平台QQ: 2270033969 一起来聊聊你们是咋用 spring cloud 的吧。欢迎关注我们的公众号获得更多的好玩JavaEE 实践 ...

March 25, 2019 · 2 min · jiezi

Spring Boot 记录 Http 请求日志

在使用Spring Boot开发 web api 的时候希望把 request,request header ,response reponse header , uri, method 等等的信息记录到我们的日志中,方便我们排查问题,也能对系统的数据做一些统计。Spring 使用了 DispatcherServlet 来拦截并分发请求,我们只要自己实现一个 DispatcherServlet 并在其中对请求和响应做处理打印到日志中即可。我们实现一个自己的分发 Servlet ,它继承于 DispatcherServlet,我们实现自己的 doDispatch(HttpServletRequest request, HttpServletResponse response) 方法。public class LoggableDispatcherServlet extends DispatcherServlet { private static final Logger logger = LoggerFactory.getLogger(“HttpLogger”); private static final ObjectMapper mapper = new ObjectMapper(); @Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); //创建一个 json 对象,用来存放 http 日志信息 ObjectNode rootNode = mapper.createObjectNode(); rootNode.put(“uri”, requestWrapper.getRequestURI()); rootNode.put(“clientIp”, requestWrapper.getRemoteAddr()); rootNode.set(“requestHeaders”, mapper.valueToTree(getRequestHeaders(requestWrapper))); String method = requestWrapper.getMethod(); rootNode.put(“method”, method); try { super.doDispatch(requestWrapper, responseWrapper); } finally { if(method.equals(“GET”)) { rootNode.set(“request”, mapper.valueToTree(requestWrapper.getParameterMap())); } else { JsonNode newNode = mapper.readTree(requestWrapper.getContentAsByteArray()); rootNode.set(“request”, newNode); } rootNode.put(“status”, responseWrapper.getStatus()); JsonNode newNode = mapper.readTree(responseWrapper.getContentAsByteArray()); rootNode.set(“response”, newNode); responseWrapper.copyBodyToResponse(); rootNode.set(“responseHeaders”, mapper.valueToTree(getResponsetHeaders(responseWrapper))); logger.info(rootNode.toString()); } } private Map<String, Object> getRequestHeaders(HttpServletRequest request) { Map<String, Object> headers = new HashMap<>(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); headers.put(headerName, request.getHeader(headerName)); } return headers; } private Map<String, Object> getResponsetHeaders(ContentCachingResponseWrapper response) { Map<String, Object> headers = new HashMap<>(); Collection<String> headerNames = response.getHeaderNames(); for (String headerName : headerNames) { headers.put(headerName, response.getHeader(headerName)); } return headers; }在 LoggableDispatcherServlet 中,我们可以通过 HttpServletRequest 中的 InputStream 或 reader 来获取请求的数据,但如果我们直接在这里读取了流或内容,到后面的逻辑将无法进行下去,所以需要实现一个可以缓存的 HttpServletRequest。好在 Spring 提供这样的类,就是 ContentCachingRequestWrapper 和 ContentCachingResponseWrapper, 根据官方的文档这两个类正好是来干这个事情的,我们只要将 HttpServletRequest 和 HttpServletResponse 转化即可。HttpServletRequest wrapper that caches all content read from the input stream and reader, and allows this content to be retrieved via a byte array.Used e.g. by AbstractRequestLoggingFilter. Note: As of Spring Framework 5.0, this wrapper is built on the Servlet 3.1 API.HttpServletResponse wrapper that caches all content written to the output stream and writer, and allows this content to be retrieved via a byte array.Used e.g. by ShallowEtagHeaderFilter. Note: As of Spring Framework 5.0, this wrapper is built on the Servlet 3.1 API.实现好我们的 LoggableDispatcherServlet后,接下来就是要指定使用 LoggableDispatcherServlet 来分发请求。@SpringBootApplicationpublic class SbDemoApplication implements ApplicationRunner { public static void main(String[] args) { SpringApplication.run(SbDemoApplication.class, args); } @Bean public ServletRegistrationBean dispatcherRegistration() { return new ServletRegistrationBean(dispatcherServlet()); } @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { return new LoggableDispatcherServlet(); }}增加一个简单的 Controller 来测试一下@RestController@RequestMapping("/hello")public class HelloController { @RequestMapping(value = “/word”, method = RequestMethod.POST) public Object hello(@RequestBody Object object) { return object; }}使用 curl 发送一个 Post 请求:$ curl –header “Content-Type: application/json” \ –request POST \ –data ‘{“username”:“xyz”,“password”:“xyz”}’ \ http://localhost:8080/hello/word{“username”:“xyz”,“password”:“xyz”}查看打印的日志:{ “uri”:"/hello/word", “clientIp”:“0:0:0:0:0:0:0:1”, “requestHeaders”:{ “content-length”:“35”, “host”:“localhost:8080”, “content-type”:“application/json”, “user-agent”:“curl/7.54.0”, “accept”:"/" }, “method”:“POST”, “request”:{ “username”:“xyz”, “password”:“xyz” }, “status”:200, “response”:{ “username”:“xyz”, “password”:“xyz” }, “responseHeaders”:{ “Content-Length”:“35”, “Date”:“Sun, 17 Mar 2019 08:56:50 GMT”, “Content-Type”:“application/json;charset=UTF-8” }}当然打印出来是在一行中的,我进行了一下格式化。我们还可以在日志中增加请求的时间,耗费的时间以及异常信息等。 ...

March 17, 2019 · 2 min · jiezi

Spring MVC之基于java config无xml配置的web应用构建

更多spring相关博文参考: http://spring.hhui.top前一篇博文讲了SpringMVC+web.xml的方式创建web应用,用过SpringBoot的童鞋都知道,早就没有xml什么事情了,其实Spring 3+, Servlet 3+的版本,就已经支持java config,不用再写xml;本篇将介绍下,如何利用java config取代xml配置本篇博文,建议和上一篇对比看,贴出上一篇地址190316-Spring MVC之基于xml配置的web应用构建<!– more –>I. Web构建1. 项目依赖对于依赖这一块,和前面一样,不同的在于java config 取代 xml<artifactId>200-mvc-annotation</artifactId><packaging>war</packaging><properties> <spring.version>5.1.5.RELEASE</spring.version></properties><dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.eclipse.jetty.aggregate</groupId> <artifactId>jetty-all</artifactId> <version>9.2.19.v20160908</version> </dependency></dependencies><build> <finalName>web-mvc</finalName> <plugins> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.12.RC2</version> <configuration> <httpConnector> <port>8080</port> </httpConnector> </configuration> </plugin> </plugins></build>细心的童鞋会看到,依赖中多了一个jetty-all,后面测试篇幅会说到用法2. 项目结构第二节依然放上项目结构,在这里把xml的结构也截进来了,对于我们的示例demo而言,最大的区别就是没有了webapp,更没有webapp下面的几个xml配置文件3. 配置设定现在没有了配置文件,我们的配置还是得有,不然web容器(如tomcat)怎么找到DispatchServlet呢a. DispatchServlet 声明同样我们需要干的第一件事情及时声明DispatchServlet,并设置它的应用上下文;可以怎么用呢?从官方找到教程{% blockquote @SpringWebMvc教程 https://docs.spring.io/spring… %}The DispatcherServlet, as any Servlet, needs to be declared and mapped according to the Servlet specification by using Java configuration or in web.xml. In turn, the DispatcherServlet uses Spring configuration to discover the delegate components it needs for request mapping, view resolution, exception handling{% endblockquote %}上面的解释,就是说下面的代码和web.xml的效果是一样一样的public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); // Create and register the DispatcherServlet DispatcherServlet servlet = new DispatcherServlet(ac); ServletRegistration.Dynamic registration = servletCxt.addServlet(“mvc-dispatcher”, servlet); registration.setLoadOnStartup(1); registration.addMapping("/"); }}当然直接实现接口的方式有点粗暴,但是好理解,上面的代码和我们前面的web.xml效果一样,创建了一个DispatchServlet, 并且绑定了url命中规则;设置了应用上下文AnnotationConfigWebApplicationContext这个上下文,和我们前面的配置文件mvc-dispatcher-servlet有点像了;如果有兴趣看到项目源码的同学,会发现用的不是上面这个方式,而是及基础接口AbstractDispatcherServletInitializerpublic class MyWebApplicationInitializer extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createRootApplicationContext() { return null; } @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); // applicationContext.setConfigLocation(“com.git.hui.spring”); applicationContext.register(RootConfig.class); applicationContext.register(WebConfig.class); return applicationContext; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected Filter[] getServletFilters() { return new Filter[]{new HiddenHttpMethodFilter(), new CharacterEncodingFilter()}; }}看到上面这段代码,这个感觉就和xml的方式更像了,比如Servlet应用上下文和根应用上下文说明上面代码中增加的Filter先无视,后续会有专文讲什么是Filter以及Filter可以怎么用b. java config前面定义了DispatchServlet,接下来对比web.xml就是需要配置扫描并注册bean了,本文基于JavaConfig的方式,则主要是借助 @Configuration 注解来声明配置类(这个可以等同于一个xml文件)前面的代码也可以看到,上下文中注册了两个Config类RootConfig定义如下,注意下注解@ComponentScan,这个等同于<context:component-sca/>,指定了扫描并注册激活的bean的包路径@Configuration@ComponentScan(value = “com.git.hui.spring”)public class RootConfig {}另外一个WebConfig的作用则主要在于开启WebMVC@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {}4. 实例代码实例和上一篇一样,一个普通的Server Bean和一个Controller@Componentpublic class PrintServer { public void print() { System.out.println(System.currentTimeMillis()); }}一个提供rest服务的HelloRest@RestControllerpublic class HelloRest { @Autowired private PrintServer printServer; @GetMapping(path = “hello”, produces=“text/html;charset=UTF-8”) public String sayHello(HttpServletRequest request) { printServer.print(); return “hello, " + request.getParameter(“name”); } @GetMapping({”/", “”}) public String index() { return UUID.randomUUID().toString(); }}5. 测试测试依然可以和前面一样,使用jetty来启动,此外,介绍另外一种测试方式,也是jetty,但是不同的是我们直接写main方法来启动服务public class SpringApplication { public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletContextHandler handler = new ServletContextHandler(); // 服务器根目录,类似于tomcat部署的项目。 完整的访问路径为ip:port/contextPath/realRequestMapping //ip:port/项目路径/api请求路径 handler.setContextPath("/"); AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(WebConfig.class); applicationContext.register(RootConfig.class); //相当于web.xml中配置的ContextLoaderListener handler.addEventListener(new ContextLoaderListener(applicationContext)); //springmvc拦截规则 相当于web.xml中配置的DispatcherServlet handler.addServlet(new ServletHolder(new DispatcherServlet(applicationContext)), “/*”); server.setHandler(handler); server.start(); server.join(); }}测试示意图如下6. 小结简单对比下xml的方式,会发现java config方式会清爽很多,不需要多个xml配置文件,维持几个配置类,加几个注解即可;当然再后面的SpringBoot就更简单了,几个注解了事,连上面的两个Config文件, ServletConfig都可以省略掉另外一个需要注意的点就是java config的运行方式,在servlet3之后才支持的,也就是说如果用比较老的jetty是起不来的(或者无法正常访问web服务)II. 其他- 系列博文web系列:Spring Web系列博文汇总mvc应用搭建篇:190316-Spring MVC之基于xml配置的web应用构建190317-Spring MVC之基于java config无xml配置的web应用构建0. 项目工程:spring-boot-demo项目: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring/200-mvc-annotation1. 一灰灰Blog一灰灰Blog个人博客 https://blog.hhui.top一灰灰Blog-Spring专题博客 http://spring.hhui.top一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛2. 声明尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激微博地址: 小灰灰BlogQQ: 一灰灰/33027978403. 扫描关注一灰灰blog知识星球 ...

March 17, 2019 · 2 min · jiezi

Spring MVC之基于xml配置的web应用构建

> 更多spring博文参考: http://spring.hhui.top/直接用SpringBoot构建web应用可以说非常非常简单了,在使用SpringBoot构建后端服务之前,一直用的是Spring + SpringMVC基于xml的配置方式来玩的,所以在正式进入SpringBoot Web篇之前,有必要看一下不用SpringBoot应该怎么玩的,也因此方便凸显SpringBoot的优越性<!– more –>I. Web 构建1. 项目依赖我们选择使用传统的SpringMVC + Tomcat/Jetty 运行war包方式来运行任务,创建一个maven项目之后,先添加上基本的依赖<artifactId>201-mvc-xml</artifactId><!– 注意这一行,我们指定war包 –><packaging>war</packaging><properties> <spring.version>5.1.5.RELEASE</spring.version></properties><dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency></dependencies>2. 项目结构对于web项目,和我们传统的不一样的地方在于,会多一个 webapp 目录,在这个目录的 WEB-INF 文件夹下,会存有几个必要的配置文件图中的三个目录,都属于比较重要的java : 存放源码resources: 项目资源文件存放地webapp: web的配置文件,资源文件默认存放地3. 配置文件说明java和resources这两个目录没啥好说的,主要来看一下webapp下面的三个xml配置文件a. web.xml在我们使用xml配置的生态体系中,这个配置文件至关重要;本节说到SpringMVC构建的应用,是在Servlet的生态上玩耍的;而web.xml这个配置文件,比如我们常见的Servlet定义,filter定义等等,都在这xml文件中实例如下<?xml version=“1.0” encoding=“UTF-8”?><web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaeehttp://java.sun.com/xml/ns/j2ee/web-app_3_1.xsd" version=“3.1”> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <!– 解决乱码的问题 –> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>上面的配置中,定义了 DispatcherServlet的名字为 mvc-dispatcher,根据规范,会有一个叫做 mvc-dispatcher-servlet.xml的配置文件,其中的配置将应用于DispatcherServlet的上下文b. mvc-dispatcher-servlet.xml这个文件主要可以用来定义Servlet相关的配置信息,比如视图解析,资源路径指定等;一个最简单的配置如下<beans xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns:aop=“http://www.springframework.org/schema/aop" xmlns:context=“http://www.springframework.org/schema/context" xmlns:beans=“http://www.springframework.org/schema/mvc" xmlns=“http://www.springframework.org/schema/beans" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!–指定扫描的包路径,自动注册包含指定注解的对象到Spring容器,并包含了 context:annotation-config 的作用–> <context:component-scan base-package=“com.git.hui.spring”/></beans>在web.xml中,context:component-scan非常非常重要,用来指定自动扫描并注册bean到容器的包路径,上面这一行配置,简单来讲可以认为做了下面几件事情扫描包 com.git.hui.spring 下所有的类,如果类上有 @Component, @Service, @Repository, @Contorller, @RestContorller, @Configuration等注解,会实例化为bean对象,并注册到Spring容器中其次就是实现DI的功能,实现bean的依赖注入接下来看一下,如果不加上面这一行,也想实现对应的效果改怎样配置呢?<!– 这个使用来激活注册的Bean,简单来讲就是使Ioc工作起来 –><context:annotation-config/><bean name=“printServer” class=“com.git.hui.spring.PrintServer”/><bean name=“helloRest” class=“com.git.hui.spring.HelloRest”/>源码后面会给出,首先是主动定义两个bean,其中 helloRest 为Controller, printServer 为一个Service,并被注入到helloRest中如果只定义了两个bean,而不加上<context:annotation-config/>,则HelloRest中的printService会是null,演示如下图此外,如果用了旧的Spring版本,直接用前面的配置,可能依然无法访问web服务,这个时候有必要加一下下面的注解; 对于使用aop,希望使用cglib代理的,需要如下配置<!– 支持mvc注解–><mvc:annotation-driven/><!– 使用cglib实现切面代理 –><aop:aspectj-autoproxy proxy-target-class=“true”/>额外说明:现在基本上不怎么用xml配置了,有更简单的注解方式,上面的配置内容了解即可c. applicationContext.xml前面的截图中,还有个配置文件,这个是干嘛的呢?DispatchServlet加载包含在web组件中的bean(如mapper,Controller,ViewResolver);我们应用中,还有些其他的Spring Bean(比如其他rpc访问的服务bean代理,db驱动组件等)则更多的是放在这个配置文件中定义当然这个里面最简单的配置内容就是啥都没有,比如我们的demo工程<beans xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://www.springframework.org/schema/beans" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>4. 实例代码配置完了之后,我们简单的定义一个reset服务用来测试,比如一个简单dean对象和一个简单的Controller简单的bean对象@Componentpublic class PrintServer { public void print() { System.out.println(System.currentTimeMillis()); }}Controller如下@RestControllerpublic class HelloRest { @Autowired private PrintServer printServer; @ResponseBody @GetMapping(“hello”) public String sayHello(HttpServletRequest request) { printServer.print(); return “hello, " + request.getParameter(“name”); }}5. 测试上面我们的web应用就搭建完毕了,然后就是把它部署起来,看下能不能愉快的玩耍了;我们有两个方法方法一:tomcat方式打包 mvn clean package -DskipTests=true ,然后target目录下会生成一个war包将war包放在tomcat的webapps目录下,然后启动tomcat进行访问即可方法二:jetty方式前面一种方式,有很多公司的服务是这么玩的,将服务达成war包丢到tomcat中,然后服务上线;然而在本地开发测试时,这样有点麻烦(当然可以通过idea配置tomcat调试法,个人感觉,依然麻烦)我们使用jetty来玩耍就很简单了,首先在pom中添加配置,引入jetty插件<build> <finalName>web-mvc</finalName> <plugins> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.12.RC2</version> <configuration> <httpConnector> <port>8080</port> </httpConnector> </configuration> </plugin> </plugins></build>然后启动方式可以使用命令: mvn jetty:run, 也可以使用idea,如下,直接双击运行或者右键选择debug模式启动然后我们愉快的启动测试过程如下到此,一个基于 Spring + SpringMVC + Jetty + xml配置的web应用就搭建起来了;下一篇我们将讲一下,纯java注解方式,抛弃xml配置又可以怎样搭建一个web应用II. 其他- 系列博文web系列:Spring Web系列博文汇总mvc应用搭建篇:190316-Spring MVC之基于xml配置的web应用构建190317-Spring MVC之基于java config无xml配置的web应用构建0. 项目工程:https://github.com/liuyueyi/spring-boot-demo项目: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring/201-mvc-xml1. 一灰灰Blog一灰灰Blog个人博客 https://blog.hhui.top一灰灰Blog-Spring专题博客 http://spring.hhui.top一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛2. 声明尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激微博地址: 小灰灰BlogQQ: 一灰灰/33027978403. 扫描关注一灰灰blog知识星球 ...

March 17, 2019 · 2 min · jiezi