SpringBoot web 开发

SpringBoot web 开发

1、寻找静态资源路径

  • WebMvcAutoConfiguration类 ,webmvc自动装配类

  • addResourceHandlers方法

    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        // 不启用默认资源处理,直接return
        if (!this.resourceProperties.isAddMappings()) {
            logger.debug("Default resource handling disabled");
            return;
        }
        ServletContext servletContext = getServletContext();
        // 请求路径:/webjars/**,映射路径:classpath:/META-INF/resources/webjars/
        addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
        /* 请求路径:staticPathPattern,没有在配置文件里配置(spring.mvc.static-path-pattern:)的话默认是/**
           映射路径:staticLocations,
           其值为"classpath:/META-INF/resources/",
                "classpath:/resources/",
                "classpath:/static/",
                "classpath:/public/"
    	*/
        addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {registration.addResourceLocations(this.resourceProperties.getStaticLocations());
            if (servletContext != null) {
                registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
            }
        });
    }
    
    // 上面方法的意思是,启用默认资源处理的情况下,静态路径可以放在classpath:/META-INF/resources/webjars/ 或者 "classpath:/META-INF/resources/"  或者 "classpath:/resources/" 或者 "classpath:/static/" 或者 "classpath:/public/"目录下,
    
  • webjars

    可以使用maven的方式引入前端资源文件,例如pom引入jquery

    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>jquery</artifactId>
        <version>3.3.1-1</version>
    </dependency>
    

    则会引入以jar包形式打包jQuery前端文件,其文件路径 classpath:/META-INF/resources/webjars/

    image

    访问地址:http://localhost:9090/webjars/jquery/3.3.1-1/jquery.js

2、默认首页

  • WebMvcAutoConfiguration类下访问首页方法welcomePageHandlerMapping

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

    image

    我们可以得到,默认的首页是 index.html

3、模板引擎Thymeleaf

引入Thymelaef

  • 方式一:创建项目时勾选上Thymeleaf依赖

  • 方式二:pom依赖引入Thymeleaf启动器

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

前端文件路径

  • 首先我们找thymeleaf的配置器,一般spring boot配置器都是 XxxProperties,所以这里我们找ThymeleafProperties

  • image

    从源码中不难得出,我们的前端html页面需要放在classpath:/templates/目录下面就行了。templates下的页面我们需要用controller来跳转

Thymeleaf 语法

  • Thymeleaf 官方文档

  • <!DOCTYPE html>
    <!-- html标签添加thymeleaf命名空间: xmlns:th="http://www.thymeleaf.org" -->
    <html xmlns:th="http://www.thymeleaf.org"> 
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        <!-- 此处使用了th:text 语法 -->
        <p th:text="${msg}"></p>
    </body>
    </html>    
    
  • 简单表达式:

    • 变量表达式: ${...}
    • 选择变量表达式: *{...}
    • 消息表达式(国际化): #{...}
    • URL表达式: @{...}
    • 代码片段插入表达式: ~{...}
  • 常量

    • 文本常量: 'one text', 'Another one!',…
    • 数字常量: 0, 34, 3.0, 12.3,…
    • 布尔常量: true, false
    • Null值: null
    • 文字标记: one, sometext, main,…
  • 文本处理:

    • 字符串拼接: +
    • 变量替换: |The name is ${name}|
  • 算术运算:

    • 二元运算: +, -, *, /, %
    • 负号: -
  • 布尔运算:

    • 且或: and, or
    • 非: !, not
  • 比较运算:

    • 比较操作符: >, <, >=, <= (gt, lt, ge, le)
    • 等式操作符: ==, != (eq, ne)
  • 条件运算符:

    • If-then: (if) ? (then)
    • If-then-else: (if) ? (then) : (else)
    • Default: (value) ?: (defaultvalue)
  • 专用记号:

    • No-Operation: _
  • 循环:th:each="item : $(list)"

  • 连接传参用括号:th:href="@{/index.html(l='zh_CN')}"

  • thymeleaf工具类:

    • string: th:if="${not #strings.isEmpty(msg)}"

    • date:${#dates.format(date, 'dd/MMM/yyyy HH:mm')}

  • 提取公共页面:

    • 标记公共页面: th:fragment="topbar"

    • 插入或替换上公共页面:th:insert="~{commons/commons :: topbar}"th:replace="~{commons/commons :: topbar}

      如果需要传递参数,可以直接追加括号th:replace="~{commons/commons :: topbar(active='home')}"

      • commons/commons是页面路径,代表commons文件夹下的commons.html页面
      • (active='home'),传递了个active参数,标记公共页面内调用到这个参数

4、实现国际化i18n

  • 国际化配置文件

    • Resource Bundle

      一堆有着相同前缀名称但有着不同语言后缀名称的属性文件的集合

      image

  • 工程配置文件配置国际化文件的路径

    spring:
      messages:
        basename: i18n.login  # 国际化配置文件位置
    
  • html 页面使用 thymeleaf 语法#{}

    <div class="panel panel-primary">
        <div class="panel-heading">
            <span class="glyphicon glyphicon-home mr-3"></span>
            <span th:text="#{login.tip}">Please sign in</span>
        </div>
        <label class="panel-body">
            <form>
                <input type="text" class="form-control mb-3" th:placeholder="#{login.username}">
                <input type="password" class="form-control mb-3" th:placeholder="#{login.password}">
                <div class="mb-3">
                    <label>
                        <input type="checkbox" > [[#{login.remember}]]
                    </label>
                </div>
                <button class="btn btn-primary btn-block" type="submit">[[#{login.submit}]]</button>
                <p class="mt-5 mb-3 text-muted">@ 2020-2021</p>
                <a class="btn btn-sm">中文</a> |
                <a class="btn btn-sm">English</a>
            </form>
        </label>
    </div>
    
  • 对于中英文切换按钮的功能实现,我们可以通过添加自定义配置实现。

    • 先给请求添加语言参数:
    <!-- thymeleaf地址后传参直接使用括号 -->
    <a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a> |
    <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
    
    • 定义自己的本地语言解析器,实现LocaleResolver接口,重写resolveLocale方法,可以参照spring中AcceptHeaderLocaleResolver类的resolveLocale写法。
    package com.jsh.demo.config;
    
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.LocaleResolver;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Locale;
    
    public class MyLocaleResolver implements LocaleResolver {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            Locale loacale = Locale.getDefault();
            if (loacale != null && request.getHeader("Accept-Language") == null) {
                return loacale;
            } else {
                // 截取请求参数,获取语言环境
                String lang = request.getParameter("l");
                if(StringUtils.hasLength(lang)){ // 如果没有传使用默认的
                    String[] langArr = lang.split("_");
                    loacale = new Locale(langArr[0], langArr[1]);
                }
            }
            return loacale;
        }
    
        @Override
        public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
    
        }
    }
    
    • 定义自己的本地语言解析器以Bean的方式注入spring容器中,就可以了.
    @Configuration
    public class MyMvcConfig implements WebMvcConfigurer {
        
        @Bean
        public LocaleResolver localeResolver(){
            return new MyLocaleResolver();
        }
    }
    

5、登录请求拦截器

在未登录的情况下,访问后台页面需要将其拦截,并重定向到登录页

package com.jsh.demo.config;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录请求拦截器
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 首先获取session值,没有session值则需要重新登录,这里的session在登录成功后会塞入用户名
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(loginUser == null){ // 没有登录
            request.setAttribute("msg", "没有权限,请先登录!");
            // 重定向到登录页
            request.getRequestDispatcher("/index").forward(request, response);
            return false;
        }else{
            return true;
        }
    }
}

重写WebMvcConfigurer接口的addInterceptors方法

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    /**
     * 配置登录拦截器,拦截未登录的请求
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/user/login", "/index", "/index.html", "/",
                        "/css/**", "/js/**", "/fonts/**"); // 哪些请求剔除,不拦截
    }
}

这里写了个简单的登录方法

package com.jsh.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttribute;

import javax.servlet.http.HttpSession;

@Controller
public class IndexController {

    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){
        String msg = "";
        if(!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            msg = "登录名或密码不能为空!";
        }else if("111".equals(password)){
            // 塞入登录session
            session.setAttribute("loginUser", username);
            return "redirect:/main.html";
        } else{
            msg = "登录名或密码错误!";
        }
        model.addAttribute("msg", msg);
        return "index";
    }
}
posted @ 2021-05-08 16:04  金盛年华  阅读(57)  评论(0编辑  收藏  举报