Java框架学习:SpringBootWeb开发

本文详细介绍了SpringBootWeb开发,包括静态资源导入,如webjars的使用;首页配置,讲解如何设置首页;模板引擎Thymeleaf的运用;扩展SpringMVC,探讨视图解析器的配置和自定义;以及国际化设置,从配置文件到页面显示和语言转换的全过程。
摘要由CSDN通过智能技术生成

静态资源导入

WebMvcAutoConfiguration类下的内部类WebMvcAutoConfigurationAdapter存在如下方法

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //如果静态资源属性被自定义了,那么记录日志,并return
	if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
    }
    Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
    CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
    //在这里注册了资源路径"/webjars/**",具体路径为"classpath:/META-INF/resources/webjars/"
    if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
                                             .addResourceLocations("classpath:/META-INF/resources/webjars/")
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    //如果没有注册staticPathPattern路径,将该路径进行注册
    //首先就是staticPathPattern,还有就是this.resourceProperties.getStaticLocations()
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
                                             .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
}

webjars
webjars有一个官网,存在一些前端的jar包,并提供maven引入的方式
在这里插入图片描述
我们可以引入jQuery的依赖,可以发现注册的目录结构与jar包中的目录结构一致
在这里插入图片描述启动项目,在地址栏输入http://localhost:8082/webjars/jquery/3.5.1/jquery.js,就可以访问jquery.js文件
第三种方式是注册staticPathPattern路径,在WebMvcProperties类可以得知staticPathPattern的值

//当前目录下的所有资源都可以识别
private String staticPathPattern = "/**";

ResourceProperties类中得知,以下四个路劲也可以访问静态资源

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

	/**
	 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
	 * /resources/, /static/, /public/].
	 */
	private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

我们可以将三个目录都补齐,如下
在这里插入图片描述
然后分别创建"1.js"用于测试,"1.js"文件内容不同
在地址栏输入http://localhost:8080/1.js,访问"1.js"文件,可得到不同目录的优先级:
resources > static > public
一般在static目录下存放静态资源

总结:

1、首先可以在配置文件中定义staticPathPattern路径,但是一旦定义那么其他两个路径失效,所以最好不要定义
2、classpath:/META-INF/resources/webjars/
3、“classpath:/META-INF/resources/”、“classpath:/resources/”、classpath:/static/、“classpath:/public/”、"/**"

首页

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                                                           FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
    return welcomePageHandlerMapping;
}

private Optional<Resource> getWelcomePage() {
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) {
    return this.resourceLoader.getResource(location + "index.html");
}

通过读源码可得首先,可以自己配置首页存放的路径,因为他需要获取StaticPathPattern,通过getWelcomePage()方法以及getIndexHtml()方法获取"index.html"页面作为首页,可以将"index.html"文件放在static目录下,这样可以在浏览器中访问

模板引擎

模板引擎的作用就是,我们写一个页面模板,比如某些值是动态的,我们把模板和数据交给模板引擎,模板引擎按照数据帮你把表达式解析,填充到指定位置。jsp就是一个模板引擎,模板引擎都是这样的思想。我们在SpringBoot中可以使用thymeleaf作为模板引擎。
ThymeleafProperties类,该类下指定了页面的前缀和后缀

//templates目录下的所有资源只能通过Controller跳转
public static final String DEFAULT_PREFIX = "classpath:/templates/";

public static final String DEFAULT_SUFFIX = ".html";

引入jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

通过模板引擎,我们就可以在Controller中访问其他页面

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model){
        model.addAttribute("msg","Hello SpringBoot");
        return "hello";
    }
}

使用thymeleaf在页面中获取域中的值

<!DOCTYPE html>
<!--引入Thymeleaf命名空间:xmlns:th="https://www.thymeleaf.org"-->
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--所有的html元素的属性都可以被thymeleaf接管,即:th:元素名-->
    <h1 th:text="${msg}"></h1>
</body>
</html>

thymeleaf官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#using-texts
thymeleaf循环取值

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model){
        //向域中存入一个集合
        model.addAttribute("msgs", Arrays.asList("aaa","bbb","ccc"));
        return "hello";
    }
}
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--th:each="元素:${集合名}"-->
    <h1 th:each="msg:${msgs}" th:text="${msg}"></h1>
</body>
</html>

扩展SpringMVC

如果你想保留这些Spring Boot MVC的配置,并进行更多的MVC配置(拦截器、格式化、视图控制器和其他功能),你可以添加@Configuration到继承了WebMvcConfigurer接口的自定义类上,但不要加@EnableWebMvc

扩展视图解析器

ContentNegotiatingViewResolver类下的resolveViewName()方法中存在如下一段代码

//如果requestedMediaTypes != null
if (requestedMediaTypes != null) {
   //获取候选视图
   	List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
	//获取最佳试图
    View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
   	if (bestView != null) {
        //返回最佳试图
      	return bestView;
   	}
}

getCandidateViews()方法(ContentNegotiatingViewResolver类下)中,会遍历视图解析器,并将视图加入视图候选中,并将视图候选的集合返回。

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");
      for (ViewResolver viewResolver : this.viewResolvers) {
         View view = viewResolver.resolveViewName(viewName, locale);
         if (view != null) {
            candidateViews.add(view);
         }
         for (MediaType requestedMediaType : requestedMediaTypes) {
            List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
            for (String extension : extensions) {
               String viewNameWithExtension = viewName + '.' + extension;
               view = viewResolver.resolveViewName(viewNameWithExtension, locale);
               if (view != null) {
                  candidateViews.add(view);
               }
            }
         }
      }
   }
   if (!CollectionUtils.isEmpty(this.defaultViews)) {
      candidateViews.addAll(this.defaultViews);
   }
   return candidateViews;
}

自定义视图解析器

//扩展SpringMVC
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
    //将自定义的视图解析器,交给Spring容器
    @Bean
    public MyViewResolver getMyViewResolver(){
        return new MyViewResolver();
    }
    //自定义一个视图解析器
    public static class MyViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return null;
        }
    }
}

所有请求都会经过DispatcherServlet,在该类中存在方法doDispatch(),我们在该方法处打上断点,debug启动程序
在这里插入图片描述点开this可以看到有一个ViewResolvers,点开后发现存在ThymeleafViewResolver(因为配置了Thymeleaf模板引擎),还存在我们自己的ViewResolver
在这里插入图片描述

为什么不能加@EnableWebMvc
//该注解核心是导入了一个类:DelegatingWebMvcConfiguration
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {

DelegatingWebMvcConfiguration类继承了WebMvcConfigurationSupport

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport

WebMvcAutoConfiguration类上存在注解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),即如果存在WebMvcConfigurationSupport类实例,WebMVC的自动配置失效。

Web开发

配置主页

扩展SpringMVC

@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //使指定请求都可以跳到index页面
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}
静态资源访问问题

一些js、css静态文件的链接在thymeleaf模板下需要使用@{…}引入

<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
国际化

首先需要将这些编码改为"UTF-8"
在这里插入图片描述

国际化配置文件

然后新建文件夹"i18n",用来存储国际化有关的配置文件,目录结构如下图所示
在这里插入图片描述
login.properties默认的语言

login.tip=请登录
login.password=密码
login.remember=记住我
login.username=用户名
login.btn=登陆

login_en_US.properties英语语言

login.tip=Please sign in
login.password=Password
login.remember=Remember me
login.username=Username
login.btn=Sign in

login_zh_CN.properties中文语言配置文件与login.properties一样。
在以上配置文件中需要配置页面中需要要国际化的信息
application.yaml中进行如下配置,声明国际化配置文件

spring:
  messages:
    basename: i18n.login
页面显示

进行完配置后,需要将这些数据在页面中显示

<!--使用#{...}将数据显示在页面上-->
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}"></h1>
<input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<input type="password" class="form-control" th:placeholder="#{login.password}" required="">
...
<input type="checkbox" value="remember-me"> [[#{login.remember}]]
...
<button class="btn btn-lg btn-primary btn-block" type="submit" >[[#{login.btn}]]</button>
语言转换

WebMvcAutoConfiguration类中存在一个国际化解析方法

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
   if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
      return new FixedLocaleResolver(this.mvcProperties.getLocale());
   }
   AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
   localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
   return localeResolver;
}

AcceptHeaderLocaleResolver类实现了LocaleResolver

public class AcceptHeaderLocaleResolver implements LocaleResolver

AcceptHeaderLocaleResolver类中还存在resolveLocale()方法

@Override
public Locale resolveLocale(HttpServletRequest request) {
   //获取默认的地区语言
   Locale defaultLocale = getDefaultLocale();
   //如果请求头中不存在"Accept-Language",那么使用默认的地区语言
   if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
      return defaultLocale;
   }
   //如果不为空,进行自定义的设置
   Locale requestLocale = request.getLocale();
   List<Locale> supportedLocales = getSupportedLocales();
   if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
      return requestLocale;
   }
   Locale supportedLocale = findSupportedLocale(request, supportedLocales);
   if (supportedLocale != null) {
      return supportedLocale;
   }
   return (defaultLocale != null ? defaultLocale : requestLocale);
}

我们可以自定义国际化解析类实现LocaleResolver接口,重写resolveLocale方法并仿照该方法自定义逻辑
首先需要前端传一个请求参数

<!--使用@{...}表示链接,在括号中传递参数-->
<a class="btn btn-sm" th:href="@{/index.html(language=zh_CN)}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(language=en_US)}">English</a>

后台对请求参数进行解析,并使用对应的地区语言

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //获取请求中的参数
        String language = request.getParameter("language");
        //如果不存在参数,使用默认的地区语言
        Locale locale = Locale.getDefault();
        //如果请求携带了国际化的参数
        if(!StringUtils.isEmpty(language)){
            String[] split = language.split("_");
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

MyLocaleResolver交给Spring容器

@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }

    //将bean交给Spring容器,自定义的国际化组件就生效了
    //注意:方法名必须为localeResolver
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值