SpringMVC实现原理和SpringBootMVC实现原理

SpringBoot、Spring、SpringMVC原理梳理 介绍SpringMVC-DishpatchServlet的初始化执行流程 阅读详情

SpringMVC实现原理和SpringBootMVC实现原理

一、MVC

MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。

MVC主要作用是降低了视图与业务逻辑间的双向耦合。

MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

  • Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

  • View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

  • Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

二、SpringMVC实现原理

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc

Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。

SpringMVC底层实现流程
底层实现流程
1.DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

我们假设请求的url为 : http://localhost:8080/SpringMVC/hello

如上url拆分成三部分:

  • http://localhost:8080 服务器域名
  • SpringMVC 部署在服务器上的web站点
  • hello 表示控制器

通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。

2.HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。

3.HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。

4.HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

5.HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

6.Handler让具体的Controller执行。

7.Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

8.HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

9.DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

10视图解析器将解析的逻辑视图名传给DispatcherServlet。

11.DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

源码简单解析MVC

在spring-webmvc的jar包下找到DispatcherServlet类,这是SpringMVC整个Web框架的核心和控制中心;
DispatcherServlet类
1.DispatcherServlet生成对象时,先对属性进行初始化的设置

public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";

request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());

2.DispatcherServlet接收到用户发来的请求,根据请求的URL调用处理器映射器来得到对应的处理器

@Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();
            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);//请求对应的处理器
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

3.处理器解析请求以后,DispatcherServlet根据解析到的信息调用处理器适配器来得到控制器

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }
        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

4.找到控制器后,由控制器Controller执行真正的处理请求的行为(根据请求调用service层对象访问数据库、得到数据、实现需求等)
并具体的执行信息(ModelAndView)返回给HandlerAdapter,HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

5.DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

 @Nullable
    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
        if (this.viewResolvers != null) {
            Iterator var5 = this.viewResolvers.iterator();

            while(var5.hasNext()) {
                ViewResolver viewResolver = (ViewResolver)var5.next();
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    return view;
                }
            }
        }
        return null;
    }

6.DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图,返回到用户。

view.render(mv.getModelInternal(), request, response);

三、SpringBootMVC实现原理

与其他Spring开发功能相似,SpringBoot为MVC的框架也实现了自动默认配置,这些自动配置由WebMvcAutoConfiguration类来实现。
在这里主要对SpringBootMVC实现视图解析器、静态资源处理、格式转换器自动配置原理进行简单记录。

视图解析器

SpringBoot中的视图解析功能由ContentNegotiatingViewResolver类来实现,由该类的实例对象来根据方法的返回值取得视图对象,再进行渲染。WebMvcAutoConfiguration类中有得到视图解析器viewResolver对象的方法

@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(name = {"viewResolver"},value = {ContentNegotiatingViewResolver.class})
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
        // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,具有较高的优先级
    resolver.setOrder(-2147483648);
    return resolver;
}

接下来可以探究ContentNegotiatingViewResolver类中解析视图(获取视图)操作的源码,类中定义了一个方法如下

@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
    RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
    Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
    List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
    if (requestedMediaTypes != null) {//获取候选的视图对象
        List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
        View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);//选择一个最合适的试图对象bestView然后返回这个对象
        if (bestView != null) {
            return bestView;
        }
    }

如何获取候选的对象,点进getCandidateViews的源码

private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
    List<View> candidateViews = new ArrayList();
    if (this.viewResolvers != null) {
        Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
        Iterator var5 = this.viewResolvers.iterator();

        while(var5.hasNext()) {
            ViewResolver viewResolver = (ViewResolver)var5.next();
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                candidateViews.add(view);
            }

            Iterator var8 = requestedMediaTypes.iterator();

            while(var8.hasNext()) {
                MediaType requestedMediaType = (MediaType)var8.next();
                List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
                Iterator var11 = extensions.iterator();

                while(var11.hasNext()) {
                    String extension = (String)var11.next();
                    String viewNameWithExtension = viewName + '.' + extension;
                    view = viewResolver.resolveViewName(viewNameWithExtension, locale);
                    if (view != null) {
                        candidateViews.add(view);
                    }
                }
            }
        }
    }

可得,该方法getCandidateViews是将所有的视图都放到List中,然后把所有的视图解析器拿来进行while循环逐个解析

如何获得最合适的视图,点进getBestView方法的源码

private View getBestView(List<View> candidateViews, List<MediaType> requestedMediaTypes, RequestAttributes attrs) {
        Iterator var4 = candidateViews.iterator();

        while(var4.hasNext()) {
            View candidateView = (View)var4.next();
            if (candidateView instanceof SmartView) {
                SmartView smartView = (SmartView)candidateView;
                if (smartView.isRedirectView()) {
                    return candidateView;
                }
            }
        }

        var4 = requestedMediaTypes.iterator();

        while(var4.hasNext()) {
            MediaType mediaType = (MediaType)var4.next();
            Iterator var10 = candidateViews.iterator();

            while(var10.hasNext()) {
                View candidateView = (View)var10.next();
                if (StringUtils.hasText(candidateView.getContentType())) {
                    MediaType candidateContentType = MediaType.parseMediaType(candidateView.getContentType());
                    if (mediaType.isCompatibleWith(candidateContentType)) {
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Selected '" + mediaType + "' given " + requestedMediaTypes);
                        }

                        attrs.setAttribute(View.SELECTED_CONTENT_TYPE, mediaType, 0);
                        return candidateView;
                    }
                }
            }
        }

        return null;
    }
}

可得,也就是在候选的view中根据需求条件得到一个最合适的视图返回;
结论:ContentNegotiatingViewResolver这个视图解析器是组合了所有的视图解析器对象来实现视图解析功能;视图解析器的组合逻辑在ContentNegotiatingViewResolver类中的initServletContext方法中定义;

protected void initServletContext(ServletContext servletContext) {
        Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
        ViewResolver viewResolver;
        if (this.viewResolvers == null) {
            this.viewResolvers = new ArrayList(matchingBeans.size());
            Iterator var3 = matchingBeans.iterator();

            while(var3.hasNext()) {
                viewResolver = (ViewResolver)var3.next();
                if (this != viewResolver) {
                    this.viewResolvers.add(viewResolver);
                }
            }
        } else {
            for(int i = 0; i < this.viewResolvers.size(); ++i) {
                viewResolver = (ViewResolver)this.viewResolvers.get(i);
                if (!matchingBeans.contains(viewResolver)) {
                    String name = viewResolver.getClass().getName() + i;
                    this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
                }
            }
        }

        AnnotationAwareOrderComparator.sort(this.viewResolvers);
        this.cnmFactoryBean.setServletContext(servletContext);
    }

静态资源处理

静态资源:前端写好的固定页面

访问webjars中的静态资源

使用SpringBoot导入静态资源,需要使用webjars导入;当我们想要访问webjars中的静态资源时,WebMvcAutoConfigurationAdapter中的方法addResourceHandlers规定了访问该静态资源的规则:

public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                if (!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
                }

            }
        }

源码中指出:当我们访问所有路径为/webjars/**的静态资源时,都需要去classpath:/META-INF/resources/webjars/里找到对应的资源

访问自己编写的静态资源

当我们需要访问自己编写的静态资源时,访问的路径是什么?再看到上面addResourceHandlers方法中有一行代码:

String staticPathPattern = this.mvcProperties.getStaticPathPattern();

这里通过getStaticPathPattern方法设置了静态资源的路径;查看WebMvcProperties类中这个方法的源码;

public String getStaticPathPattern() {
        return this.staticPathPattern;
    }

查看staticPathPattern这个属性在构造器中的初始化:

this.staticPathPattern = "/**";

可得,该类中构造器对staticPathPattern(静态资源路径)的初始化为"/**",访问目录下的任何资源;
而这个属性的定义会找WebProperties这个类中内部类Resources的getStaticLocations()方法;

 public String[] getStaticLocations() {
            return this.staticLocations;
        }

Resources是WebProperties类中的一个静态内部类,其构造器对staticLocations的初始化值为一个常量;

public Resources() {
            this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

而该常量属性在Resources类中的定义为

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

至此,我们得知了静态资源自动配置的默认访问路径;可知:这里声明了访问静态资源时,查找静态资源的路径目录,即上面定义的静态String[]数组里的内容

“classpath:/META-INF/resources/”

“classpath:/resources/”

“classpath:/static/”

“classpath:/public/”

因此,在这四个目录下存放的静态资源可以被识别和访问,我们可以在根目录resources下创建相应的文件夹来存放静态资源;
eg:访问http://localhost:8080/hello.js,就会在以上路径目录中查找相对应的文件

格式转换器

在WebMvcAutoConfiguration类中定义了格式转换的方法

@Bean
        public FormattingConversionService mvcConversionService() {
            Format format = this.mvcProperties.getFormat();
            WebConversionService conversionService = new WebConversionService((new DateTimeFormatters()).dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
            this.addFormatters(conversionService);
            return conversionService;
        }

getXxx()方法就规定了相应的格式;

以上,需要注意的是,spring中导入的web-mvc的jar包不同版本源码可能会有所不同。SpringBoot版本不同,mvc配置类中的源码也会有所差别。

SpringMVC详解——SpringBoot扩展SpringMVC原理全面接管SpringMVC ** 如果想在SpringBoot中扩展一些SpringMVC的配置,例如需要配置自定义的视图解析器或拦截器等,需要怎么实现呢?** 例如,自定义一个视图解析器: @Configuration public class MyConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addVie 阅读详情

相关推荐

SpringBoot】初学SpringMVC必备知识详解

SpringMVC是基于构建的原始Web框架,从一开始就包含在Spring框架中。它的正式名称为“”,通常简称为SpringMVCSpringMVC是一个Web框架SpringMVC是基于ServletAPI的为了更加理解SpringMVC,我们需要知道什么是MVC。

m0_74823094的博客 884

SpringMvc原理详解

SpringMvc原理详解一、SpringMVC简介:二、Spring流程三、组件进行详细的介绍:四、具体步骤:六、通过代码进一步了解SpringMVC原理 一、SpringMVC简介: Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。 与之相反的是基于组件的、事

我是泛滥 1819

入门 SpringMVC:Web 开发的经典选择与搭建第一个SpringBootMVC项目

SpringMVC 是 Spring 框架的子模块,用于构建基于 MVC 设计模式的 Web 应用。它通过注解简化配置,将请求处理、业务逻辑视图展示分离,适合初学者入门。SpringMVC 的核心工作流程包括请求通过 DispatcherServlet 调度,定位到目标 Controller,执行方法并返回视图或数据。常用注解如 @Controller、@RequestMapping、@ResponseBody 等,帮助开发者快速实现请求映射、参数绑定、页面跳转等功能。

hello world 1989

深入理解SpringMVC工作原理,像大牛一样手写SpringMVC框架

SpringMVC是Spring家族中的元老之一,它是一个基于MVC三层架构模式的Web应用框架,它的出现也一统了JavaWEB应用开发的项目结构,从而避免将所有业务代码都糅合在同一个包下的复杂情况。在该框架中通过把M/Model模型:由等JavaBean构成,主要负责业务逻辑处理。V/View视图:负责向用户进行界面的展示,由等组成。控制器:主要负责接收请求、调用业务服务、根据结果派发页面。SpringMVC贯彻落实了MVC思想,以分层工作的模式,把整个较为复杂的web。

m0_73311735的博客 614

SpringMVC原理

Spring MVC的功能组件 Spring通过一系列组件实现功能,这些组件包括DispatcherServlet(前端控制器)、HandlerMapping(处理器映射器)Handler(处理器)、HandlAdapter(处理器适配器)、ViewResolver(视图解析器)等。 DispatcherServlet(前端控制器) 前端控制器负责拦截客户端请求并分发给其他组件,它是整个流程控制的中心,负责调度其他组件的执行,降低各组件之间的耦合,提升整体效率。前端控制器由框架提供,在程序运行过程中自动实

笔记别偷看 5569

SpringBoot嵌入SpringMVC原理分析

承接上文。 在上一篇文章中,我们介绍到了SpringBoot是如何整合Tomcat的。我们知道在SpringBoot项目中可以使用SpringMVC的注解,比如@Controller@RequestMapping注解。既然我们没有配置SpringMVC那么mvc的功能又是怎么起作用呢? 自动配置(一) 自动配置DispacherServletDispacherServletRegistration 首先找到SpringMVC的自动配置类 org.springframework.boot.autoconf

weixin_43169335的博客 1379

spring,springbootspringmvc底层原理解析

一、概念 1、Spring Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,维护bean与bean之间的关系。其核心就是控制反转(IOC),面向切面(AOP) ,简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。 2、SpringMVC Spring 框架提供了构建 We...

架构大数据双料架构师的博客 958

springbootMVC理解概述

https://tyshawnlee.blog.csdn.net/article/details/79169148?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-3.highlightwordscore&depth_1-utm_source=distribute.pc_relevant.none-ta

qq_38642731的博客 139

【Java面试】七、SpringMvc的执行流程、SpringBoot自动装配原理

旧项目中,未前后端分离时,用到JSP,相关流程为: 请求达到前端控制器DispatcherServlet,它相当于一个调度中心,会加载处理器映射器、处理器适配器、视图解析器。DispatcherServlet被Tomcat容器初始化,所有的请求先经过它。 DispatcherServlet向处理器映射器去查询handler,即查询这个接口该调哪个Controller的哪个方法。处理器映射器里以key-value形式存了接口路径合类名+方法名 流程总结:不再返回一个ModelAndView,而是返回一个J

llg___的博客 1505

SpringBootMVC配置

在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制。 只有把这些都搞清楚了,我们在之后使用才会更加得心应手。途径一:源码分析,途径二:官方文档! 地址 :https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration ContentNegotiating

qq_43535568的博客 319

SpringBoot简单功能分析,静态资源访问静态资源配置原理解析

SpringBoot 关于SpringMVC自动配置的概述、静态资源访问、欢迎页、自定义Favicon 静态资源配置原理的解析

m0_62946761的博客 7321

JavaEE_03_SpringMVC基础

重点SpringMVC处理逻辑及代码实现;Swagger UI框架使用。难点Spring Web MVC核心组件;SpringBoot MVC代码实现

weixin_42788897的博客 85

SpringBoot——MVC原理

1)、在自动配置很多组件的时候,先看容器中有木有用户自己配置的(@Bean,@Component)如果有就是用用户配置的,如果没有就是用自动配置的,因为底层使用了@ConditionalOnMiss注解来判断,容器中是否已经存在此类配置。2)、如果有些组件可以配置多个,比如视图解析器(ViewResolver)将用户配置的自己默认的组合起来。继承抽象类既保留了所有的自动配置,也能用我们扩展的配置;类时,就不会导入自动配置的类了,第二步导入的就是这个类。的自动配置我们的扩展配置都会起作用;

程序猿进阶 2630

SpringMVC执行流程

DispatcherServlet:前端控制器,不需要工程师开发,由框架提供作用:统一处理请求响应,整个流程控制的中心,由它调用其它组件处理用户的请求作用:根据请求的url、method等信息查找Handler,即控制器方法Handler:处理器,需要工程师开发作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供作用:通过HandlerAdapter对处理器(控制器方法)进行执行。...

一个菜鸡的博客 1905

netty springmvc_01面试常问:SpringMVCSpringBoot,SpringCloud有什么区别联系?

简单介绍Spring是一个轻量级的控制反转(IoC)面向切面(AOP)的容器框架。Spring使你能够编写更干净、更可管理、并且更易于测试的代码。Spring MVC是Spring的一个模块,一个web框架。通过Dispatcher Servlet, ModelAndView View Resolver,开发web应用变得很容易。主要针对的是网站应用程序或者服务开发——URL路由、Sessi...

weixin_39793813的博客 434

毕业设计|springbootMVC模式红色革命文物征集管理系统-|免费|代码讲解

如图5.2显示的就是文物信息管理页面,此页面提供给管理员的功能有:查看已发布的文物信息数据,修改文物信息,文物信息作废,即可删除,还进行了对文物信息名称的模糊查询 文物信息信息的类型查询等等一些条件。如图5.3显示的就是论坛信息管理页面,此页面提供给管理员的功能有:根据论坛信息进行条件查询,还可以对论坛信息进行新增、修改、查询操作等等。如图5.1显示的就是用户信息管理页面,此页面提供给管理员的功能有:用户信息的查询管理,可以删除用户信息、修改用户信息、新增用户信息,1.万字文档展示(部分)

2401_85731605的博客 350

SpringMVC参数绑定类型使用

目录 1、SpringMVC 参数绑定 2、默认支持的类型 3、基本数据类型的绑定 4、包装数据类型的绑定 5、POJO(实体类)类型的绑定 参数绑定,简单来说就是客户端发送请求,而请求中包含一些数据,那么这些数据怎么到达 Controller ?这在实际项目开发中也是用到的最多的,那么 SpringMVC 的参数绑定是怎么实现的呢?下面我们来详细的讲解。 1、SpringMVC 参数绑定   在 SpringMVC 中,提交请求的数据是通过方法形参来接收的。从客户端请求的 key/value 数据,经过.

athga的博客 592
下一篇: Carp前端开发文档
Jiraiya_sensei
博客等级 码龄7年 2粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值