Spring Web MVC系统学习笔记

参考资料:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-features

1 Spring Web MVC框架介绍

DispatcherServlet是框架的设计核心,他负责分发请求给处理器、包括可配置的处理映射,视图表现,本地化,时区以及可上传文件式的主题。
默认的处理器基于注解@Controller和@RequestMapping,提供一个相当大幅度的灵活度处理的方法。
通过Spring 3.0,@Controller能允许你通过@PathVariable注解创建一个RESTful的web站点和应用程序。
通过Spring MVC我们可以用任何对象作为控制对象或基于表单的对象,我们不需要实现某框架的特殊接口或继承类。Spring的数据绑定具有很高的灵活性,比如它可以处理类型错误如验证错误一样,使得通过应用程序验证,而不是系统错误。
Spring MVC的页面处理也非常灵活。Controller不仅是准备一个model的含数据的map的响应,也可以选择一个视图名,并且它可以直接写出response流并且完成请求。
视图(View)名可通过文件扩展名配置或者接受头内容的类型转让,包括bean的名字,properties问卷或者通过自定义的ViewResolver接口。
模型(Model)是一个Map接口,它考虑到完全抽象的表现层技术。你可以直接将其表示成JSP,Velocity,Freemarker,或者生成XML,JSON,Atom,和许多其他内容类型。Model的Map可以简单的转换为一个合适的格式,如JSP请求或者Velocity模板。

1.1 Spring Web MVC功能

  • 清晰的分工
  • 强力直观的配置
  • 灵活的,无强制配置,适应性强
  • 可重用的业务代码
  • 自定义的数据绑定和验证
  • 自定义的处理器匹配和页面响应
  • 灵活的模型转换
  • 自定义的时区,本地化以及主题策略
  • 一个简单并强大的JSP标签库,提供了支持功能
  • 对象的生命周期是包括在当前的HTTP request或者 HTTP Session中的

2 The DispatcherServlet

Spring Web MVC框架像许多其他的web MVC框架一样,基于request,并设计成围绕着核心Servlet来分发请求到控制端,控制端提供功能性。
如下图,DispatcherServlet承担着Front controller的任务。
这里写图片描述

DispatcherServlet是一个Servlet,他继承自HttpServlet的基类,并且声明自web.xml。我们需要匹配请求来让DispatcherServlet处理,即<url-pattern>,

web.xml :

<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>/example/*</url-pattern>
    </servlet-mapping>

</web-app>

在Servlet3.0+的环境下,也可以通过编码的手段来配置:

编码配置(等价于XML配置):

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }

}

WebApplicationInitializer是Spring MVC提供的基类来初始化Servlet 3的容器。

每一个DispatcherServlet都有一个自己的WebApplicationContext,而这个WebApplicationContext 继承的所有实例都定义在根WebApplicationContext中。
这里写图片描述

在初始化DispatcherServlet时,Spring MVC寻找一个[servlet-name]-servlet.xml的文件在WEB-INF下,比如example-servlet.xml

他也可以通过配置属性contextConfigLocation来自定义配置文件目录:

<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

WebApplicationContext是ApplcationContext基于web应用功能的扩展,它不同于ApplicationContext在可以使用主题,并且可以知道哪个Servlt是被联系的。WebApplicationContext被绑定在ServletContext中,通过RequestContextUtils类中的静态方法,你可以查看WebApplicationContext。

2.1 WebApplicationContext中特殊的Bean类型

Spring的DispatcherServlet使用特殊的Bean去处理请求以及返回页面。我们可以选择单个或多个使用这些bean在WebApplicationContext中。Spring MVC准备了一个默认bean列表,所以当你没有配置时,你并不需要初始化他们。

Bean Type说明
HandlerMappingMaps来自请求到处理器和一个预先和延后处理器(即拦截器),基于一些可改变的规则来自HandlerMapping实现。最常用的实现支持注解的控制器
HandlerAdapter帮助DispatcherServlet执行一个处理器去匹配不被理会的请求。例如一个注解的controller需要处理大量的注解,因此HandlerAdpater的主要用途是隐藏DisptatcherServlet的细节
HandlerExceptionResolver匹配错误至页面
ViewResolver处理基于String的View名字至存在的View页面
LocaleResolver&LocaleContextResolver用于国际化
ThemeResolver提供能用的Web应用主题
MulitipartResolver解析上传文件请求
FlashMapManager保存并搜索“input”和“output”,能用于传递属性至不同的request,经常用于重定向

2.2 默认的DispatcherServlet配置

所有的特殊Bean都有配置,在org.springframework.web.servlet中的DispatcherServlet.properties。

2.3 DispatcherServlet的处理顺序

  • 获取WebApplicationContext并被绑定为一个控制器以及其他元素可使用的属性。
  • 本地的解析器被绑定到请求。
  • 主题解析器被绑定。
  • 如果指定了复合文件解析器,则请求将检查符合文件
  • 搜索适当的处理器
  • 如果返回了一个model,则提供一个view。

DispatcherServlet可初始化这几个属性:contextClass(自定义的类),contextConfigLocation(配置文件),namespace(默认为[servlet-name]-servlet)。


3 实现Controllers

@Controller
public class HelloWorldController {

    @RequestMapping("/helloWorld")
    public String helloWorld(Model model) {
        model.addAttribute("message", "Hello World!");
        return "helloWorld";
    }
}

@Controller和@RequestMapping这2个注解提供了灵活的方法名即签名配置。
在以上例子中方法需要接受一个Model类型的形参,并且返回一个String类型的视图名。

3.1 通过@Controller来定义controller

只需要启动扫描注解包就可以使用@Controller来定义包

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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">

    <context:component-scan base-package="org.springframework.samples.petclinic.web"/>

    <!-- ... -->

</beans>

3.2 通过@RequestMapping来匹配请求

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    /* 对于/appointments的HTTP的GET请求调用这个方法 */
    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @RequestMapping(value="/{day}", method = RequestMethod.GET)
    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }

    /* 对于/appointments/new 的HTTP的GET请求调用这个方法 */
    @RequestMapping(value="/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();
    }

    /* 对于/appointments的HTTP的POST请求调用这个方法 */
    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm appointment, BindingResult result) {
        if (result.hasErrors()) {
            return "appointments/new";
        }
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}

以上例子使用了很多@RequestMapping注解,第一个在类级别下的@RequestMapping(“/appointments”)说明所有的处理方法都是与appointments相关的。
get表明只接受get请求。

用@RequestMapping注解来修饰类级别并不是必须的:

@Controller
public class ClinicController {

    private final Clinic clinic;

    @Autowired
    public ClinicController(Clinic clinic) {
        this.clinic = clinic;
    }

    @RequestMapping("/")
    public void welcomeHandler() {
    }

    @RequestMapping("/vets")
    public ModelMap vetsHandler() {
        return new ModelMap(this.clinic.getVets());
    }

}

URL Template Patterns

URL模板可以用在@RequestMapping下的方法。

例如http://www.example.com/users/{userId} 可将fred注入到域中http://www.example.com/users/fred

在Spring MVC中使用@PathVariable注解在形参中,可将其绑定到url模板中的属性。
详细例子:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    model.addAttribute("owner", owner);
    return "displayOwner";
}

或者:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
    // implementation omitted
}

在类级别使用url模板

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

    @RequestMapping("/pets/{petId}")
    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
        // implementation omitted
    }

}

当使用findPet( )方法后URL:/owners/42/pets/21.

@PathVariable的类型为基本类型。

URL模板也可以匹配正则表达式

3.3 定义@RequestMapping 处理器方法

@RequestMapping处理方法有很高的灵活性。

支持方法参数类型
- Request和Reponse对象(Servlet API),比如ServletRequest和HttpServletRequest
- Session object(Servlet API):HttpSession
- WebRequest或者NativeWebRequest
- Local,LocaleResolver/LocaleContextResolver
- TimeZone/ZoneId
- InputStream/Reader,request内容
- OutputStream/Writer,response内容
- HttpMethod,Http请求
- Principal:包含当前的认证用户
- @PathVariable:用于URL模板的变量
- @MatrixVariable:用于URL的键值配对的片段
- @RequsetParam:用于指定的Servlet request参数
- @RequestHeader:用于指定的Servlet request的HTTP头
- @RequestBody:用于指定的HTTP request的body
- @RequestPart:用于复合数据请求
- HttpEntity<?>参数用来访问Servlet request HTTP headers和contensts
- Map/Model,保存了视图所需要的模型数据
- RedirectAttributes:特定的重定向的属性
- Errors/BindingResult: 验证结果
- SessionStatus:
- UrlComponentsBuilder
如果使用Errors或者BindingResult,需要如下顺序:

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }

支持的返回类型
- ModelAndView类型,@ModelAttrivute描述的方法
- Model类型,@ModelAttribute描述的数据方法
- Map类型
- View类型
- String类型,对应view的名字
- void,相应自己

通过@RequestParam来绑定请求参数

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }
    // ...
}

3.4 异步请求处理


4 处理匹配

我们通过@RequestMapping注解来处理匹配,然而,知道所有的HandlerMapping类都是继承自AbstractHandlerMapping可以自定义他们的行为:
- interceptors:拦截器
- defaultHandler:默认的处理器
- order:基于order属性
- alwaysUseFullPath。
- urlDecode,默认为true

<beans>
    <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="interceptors">
            <bean class="example.MyInterceptor"/>
        </property>
    </bean>
<beans>

4.1 通过HandlerInterceptor来过滤请求

<beans>
    <bean id="handlerMapping"       class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="interceptors">
            <list>
                <ref bean="officeHoursInterceptor"/>
            </list>
        </property>
    </bean>

    <bean id="officeHoursInterceptor"
            class="samples.TimeBasedAccessInterceptor">
        <property name="openingTime" value="9"/>
        <property name="closingTime" value="18"/>
    </bean>
<beans>
package samples;

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

    private int openingTime;
    private int closingTime;

    public void setOpeningTime(int openingTime) {
        this.openingTime = openingTime;
    }

    public void setClosingTime(int closingTime) {
        this.closingTime = closingTime;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(HOUR_OF_DAY);
        if (openingTime <= hour && hour < closingTime) {
            return true;
        }
        response.sendRedirect("http://host.com/outsideOfficeHours.html");
        return false;
    }
}

5 处理页面

对于Spring处理视图,ViewResolver和View很重要,ViewResolver提供一个匹配在视图名和视图文件,view接口记录了request的准备已经处理request到视图。

5.1 通过ViewResolver接口处理views

ViewResolver:

ViewResolverDescription
AbstractCachingViewResolver处理器缓存了一些视图,通常这些视图需要在使用前预处理
XMLViewResolver实现ViewResolver能接受配置文件写在XML,默认的配置文件在/WEB-INF/views.xml
ResourceBundleViewResolver使用属性文件实现ViewResolver,默认为views.properties
UrlBasedViewResolver直接将结果映射到URL
InternalResourceViewResolverUrlBasedViewResolver的次级类
VelocityViewResolver支持VelocityView
ContentNegotiationgViewResolver实现ViewResolver接口,通过request的文件名或者accept头来生成视图

URLBasedViewResolver

<bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

ResourceBundleViewResolver

<bean id="viewResolver"  class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="basename" value="views"/>
    <property name="defaultParentView" value="parentView"/>
</bean>

5.2 ViewResolver链

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="order" value="1"/>
    <property name="location" value="/WEB-INF/views.xml"/>
</bean>

<!-- in views.xml -->

<beans>
    <bean name="report" class="org.springframework.example.ReportExcelView"/>
</beans>

5.3 重定向views

RedirectView

@RequestMapping(value = "/files/{path}", method = RequestMethod.POST)
public String upload(...) {
    // ...
    return "redirect:files/{path}";
}

The redirect: prefix

redirect:http://myhost.com/some/arbitrary/path

The forward: prefix

5.4 ContentNegotiatingViewResolver

ContentNegotiatingViewResolver 并不自己处理视图,而是委托给其他的视图处理器。
example:

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="atom" value="application/atom+xml"/>
            <entry key="html" value="text/html"/>
            <entry key="json" value="application/json"/>
        </map>
    </property>
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <property name="suffix" value=".jsp"/>
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
        </list>
    </property>
</bean>

<bean id="content" class="com.foo.samples.rest.SampleContentAtomView"/>

6 使用闪存属性

闪存属性可以提供一个方法给请求去保存。
Spring MVC有两种主要的方式来支持闪存属性,FlashMap用来保存闪存属性当FlashMapManager用来保存,检索以及管理FlashMap的属性。


7 搭建URL

Spring MVC提供了一个机制去搭建编写URL - UrlComponentsBuilder和UriComponents

扩展并加密URL的例子:

UriComponents uriComponents = UriComponentsBuilder.fromUriString(
        "http://example.com/hotels/{hotel}/bookings/{booking}").build();

URI uri = uriComponents.expand("42", "21").encode().toUri();

UriComponents是不可变的,并且expand( )和encode( )执行将返回一个新的实例。

UriComponents uriComponents = UriComponentsBuilder.newInstance()
        .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()
        .expand("42", "21")
        .encode();

8 本地化

9 使用主题

10 Spring的文件上传

11 处理错误

12 web安全

13 约定优先配置原则

13.1 控制器的匹配

  • WelcomeController 匹配 /welcome*
  • HomeController 匹配 /home*
  • IndexController 匹配 /index *
  • RegisterController 匹配 /register*

  • AdminController匹配/admin/*

  • CatalogController匹配/catalog/*

13.2 模型的ModelMap

  • x.y.User实例生成user
  • x.y.Registration生成registration
  • java.util.HashMap的实例生成hashMap,我们需要明确这个名字,因为hashMap是违背直觉
  • null作为result会跑出一个IllegalArgumentException异常

  • An x.y.User[] array with zero or more x.y.User elements added will have the name userList generated.

  • An x.y.Foo[] array with zero or more x.y.User elements added will have the name fooList generated.
  • A java.util.ArrayList with one or more x.y.User elements added will have the name userList generated.
  • A java.util.HashSet with one or more x.y.Foo elements added will have the name fooList generated.
  • An empty java.util.ArrayList will not be added at all (in effect, the addObject(..) call will essentially be a no-op).

14 ETag支持

15 基于代码的servlet容器配置


16 SpringMVC的配置

16.1 启动MVC的JAVA配置或XML命名空间

基于@Configuration的配置

@Configuration
@EnableWebMvc
public class WebConfig {

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven />

</beans>

16.2 自定义提供的配置

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    protected void addFormatters(FormatterRegistry registry) {
        // Add formatters and/or converters
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // Configure the list of HttpMessageConverters to use
    }

}

16.3 拦截器配置

通过java配置:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleInterceptor());
        registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }

}
<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/secure/*"/>
        <bean class="org.example.SecurityInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

16.4 内容导航

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(true);
    }
}
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="true" />
    <property name="mediaTypes" >
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

16.5 View Controllers

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("home");
    }

}
<mvc:view-controller path="/" view-name="home"/>

16.6 View Resolvers

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.jsp();
    }

}
<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:jsp />
</mvc:view-resolvers>
<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:freemarker cache="false" />
</mvc:view-resolvers>

<mvc:freemarker-configurer>
    <mvc:template-loader-path location="/freemarker" />
</mvc:freemarker-configurer>

16.7 静态资源服务

<mvc:resources mapping="/resources/**" location="/public-resources/"/>
<mvc:resources mapping="/resources/**" location="/public-resources/">
    <mvc:resource-chain>
        <mvc:resource-cache />
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

16.8 默认的servlet

<mvc:default-servlet-handler/>
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>

16.9 路径匹配

<mvc:annotation-driven>
    <mvc:path-matching
        suffix-pattern="true"
        trailing-slash="false"
        registered-suffixes-only="true"
        path-helper="pathHelper"
        path-matcher="pathMatcher" />
</mvc:annotation-driven>

<bean id="pathHelper" class="org.example.app.MyPathHelper" />
<bean id="pathMatcher" class="org.example.app.MyPathMatcher" />

16.10 高级自定义配置

16.11 自定义MVC命名控制

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值