SpringBoot学习Day04——web

SpringBoot与web

1.对静态资源的映射

1.1 webjars

以jar包的形式引入web静态资源,webjars官网里面有一些常用的web前端框架的依赖。

1.2 本地资源

将静态资源(js、css、images)放在下列文件夹中即可,推荐放在static文件夹下。

class:/META-INF/resources/,
class:/resources/,
class:/static/,
class:/public/,
当前项目跟路径

如果要直接访问静态文件直接在浏览器输入:localhost:8080:/js/FileName.js就可以访问,如果访问显示找不到路径,可以考虑重现启动项目和刷新maven的pom.xml。

1.3 欢迎页

默认的欢迎页是 index.html 将这个文件放在静态资源下,再次访问localhost:8080就会直接访问到index.html

1.4 图标

springboot项目默认使用的图标是spring的叶子图标,如果想要修改自己的图标,只需要将图标名称改为:favicon.ico 。如果不显示可以尝试刷新maven的pom.xml。

2.模板引擎 Thymeleaf

2.1 Thymelefa

2.1.1 依赖
   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
2.2.2 使用

只要把html界面放在类路径下的themlates文件夹下,thymeleaf就会自动渲染。

2.2.2.1 导入名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2.2.2.2 语法规则

th:任意html属性;来替换html的值
图片来自B站截图

2.2.2.3 表达式语法
  1. ${…}:获取变量值
  2. *{…}:变量的选择表达式;与${…}基本相同,配合th:object来使用。
使用*{...}
<div th:object=${session.user}>
	<p>*{name}</p>
	<p>*{address}</p>
</div>
不使用
<div>
	<p>${session.user.name}</p>
	<p>${session.user.address}</p>
</div>
  1. #{…}:获取国际化内容
  2. @{…}:定义URL
<a href="index.html"
th:href="@{localhost:8080/hello(name=${user.name})}>

</a>
  1. ~{…}:片段引用
  2. 在表达式中还支持:字面量、文本操作、数学运算、布尔运算、比较运算、条件运算(三元运算符)。
2.2.2.4 Thymeleaf语法小demo

controller:

 @RequestMapping("/success")
    public String success(Map<String ,Object> map){
        map.put("hello","<h1>你好!</h1>");
        map.put("users", Arrays.asList("吴彦祖","梁朝伟","彭于晏"));
        return "success";
    }

html:

<!DOCTYPE html>
<html lang="en"  >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>成功</h1>


    <div th:text="${hello}"></div>
    <hr>
    <div th:utext="${hello}"></div>
    <hr>

<!--    th:each写在的标签上,每次遍历都会生产改标签。-->
    <h2 th:text="${user}" th:each="user : ${users}"></h2>
    <hr>

<!--    th:text/th:utext的行内写法:[[${user}]]/[(${user})]-->
    <div>
        <span th:text="${usera}" th:each="usera : ${users}"></span>
    </div>
</body>
</html>

成果:
在这里插入图片描述

2.2.2.5 小补充

th:text的行内写法:[[${user}]]
th:utext的行内写法:[(${user})]

3.扩展SpringMVC功能

SpringBoot2.* 版本中如果自己扩展SpringMVC配置继承WebMvcConfigurer类之后,就会关闭SpringBoot的自动配置,就会找不到引入的静态文件。所以改为实现WebMvcConfigurer接口就可以实现在SpringBoot1.*中继承WebMvcConfigurationAdapter一样的功能。

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
//        super.addViewControllers(registry);
//        在请求/at路径时,会跳转到success界面。
        registry.addViewController("/at").setViewName("success");
    }

既保留的所有的自动配置也能用扩展的。
SpringMVC的自动配置和自己的扩展配置都能调用。

全面接管SpirngMVC:
关闭SpringBoot对SpirngMVC的自动配置,所有的东西都有自己来配置。只需要在配置类中添加@EnableWebMvc

4. 一个crud的demo

4.1 引入静态资源

将本地的css、js、image放在resources/static
引入Bootstrap依赖:

<!--        bootstrap 依赖-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.0.0</version>
        </dependency>

修改html代码中引用本地css、image、js的路径:

<!--		jar包依赖中的bootstrap-->
<link href="asserts/css/bootstrap.min.css" th:href="@{webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<!--		static下的signin.css-->
<link href="asserts/css/signin.css" th:href="@{asserts/css/signin.css}" rel="stylesheet">

4.2 国际化

4.2.1 编写国际化配置文件

resources文件中新建文件夹i18n然后在i18n中新建文件夹index(被国际化界面的名称)然后新建index.properties再新建index_en(语言简称)_US(国家简称).propertices之后idea就会识别是要做国际化,会变成如图所示的文件夹名称;再右键index文件夹就会在new里面出现add propertices,添加即可;idea提供了语言可视化,将想要国际化的部分命名和添加默认显示内容,特定国家显示内容就ok;如果使用可视化工具会报错,只能编写配置文件了。

index_zh_CN.properties:

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

index.properties:

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

index_en_US.properties:

index.btn=login
index.password=password
index.remember= remember me
index.tip=Please Sing in
index.username=username

idea国际化可视化:
在这里插入图片描述
文件结构
在这里插入图片描述

4.2.2 配置国际化配置文件

在SpringBoot中自动配置了国际化,只需要将国际化的配置文件放在根目录下的message文件夹下,但是创建的文件夹为i18n,所以需要去主配置文件下指定:spring.messages.basename=i18n.index

4.2.3 界面获取国际化的值

使用thymeleaf模板中的#{Object.value}可以获取国际化文件中的内容,并且会根据浏览器的设置来显示国际化内容。
乱码原因:idea中的properties文件没有进行编码最终会转换为Ascii码。
解决方法:file->setting->搜索file encoding->将下面改为utf-8并且选上自动转为ascii
在这里插入图片描述
可以了。

4.2.4 自己选择语言
  1. 编写自己的本地语言解析
public class MyLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String  l =null;
        l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if (!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

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

    }
}
  1. 在SpringMVC配置文件中导入容器
  @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
  1. 前台传入语言参数
<a class="btn btn-sm" th:href="@{/(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/(l='en_US')}">English</a>

4.3 登录

在开发期间关闭thymeleaf的缓存spring.thymeleaf.cache=false,就可以使用ctrl+f9对项目于进行重新编译,不需要重启项目,就可以看到界面的变化,可以节省时间。

controller:

@Controller
public class LoginController {
    @PostMapping(value = "/user/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Map<String ,Object> map){
        if (!StringUtils.isEmpty(username) && "123456".equals(password)){
//            防止表单重复提交,重定向到主页
            return "redirect:/main.html";
        }
        map.put("msg","用户名或者密码错误");
        return "index";
    }
}

在mvc配置中新增:

 registry.addViewController("/main.html").setViewName("dashboard");

拦截器进行登录检查

public class LoginHandleInterceptor implements HandlerInterceptor {
//    目标方法执行之前进行检查
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object username = request.getSession().getAttribute("username");
        if (username == "" || username == null){
//            未登录
            request.setAttribute("msg","没有权限,请登录");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else {
            return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

在SpringMVC配置中注册拦截器:

//    注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandleInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/index.html","/","/user/login");
    }

4.4 查询全部员工

在开发时有些html代码是重复的,那么就可以用:
thymeleaf抽取模板

<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
			<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Company name</a>
			<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
			<ul class="navbar-nav px-3">
				<li class="nav-item text-nowrap">
					<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
				</li>
			</ul>
		</nav>

thymeleaf引入抽取的模板
有三种方式:

<div th:insert="~{dashboard::topbar}"></div>
<div th:replace="~{dashboard::topbar}"></div>
<div th:include="~{dashboard::topbar}"></div>
  1. insert:将公共片段插入指定元素中
  2. replace:将声明引入的元素替换为公共片段
  3. include:将被引入的片段内容包含进标签中。

就写到这里。

5.错误处理机制

5.1 错误处理机制原理

一旦系统发生4xx或者5xx的错误,ErrorPageCustomizer就会生效,来到error请求进行处理;BasicErroorController会处理默认的error请求,里面有两个方法,分别返回jsonhtml
DefaultErrorViewResolver会响应界面,如果错误存在就会返回界面,否则就返回null;
SpringBoot就会去找error下的错误代码界面;可以使用模板引擎去解析界面;

5.2 自定义错误处理界面

5.2.1 有模板引擎

templates下新建文件夹error,在新建错误代码文件(404.html…),发生状态码的错误就会响应指定的界面,如果命名为4xx.html那么如果出现4**的错误就会返回到4xx.html5xx也一样;精确状态码优先于xx界面。

5.2.2 没有模板引擎

在静态资源文件夹下找,

5.2.3 以上都没没有

来到SpringBoot默认的错误界面

5.3 自定义Json数据

返回自定义的Json数据,新建一个异常处理器,但是现在的代码有一个缺点,并不会自适应返回Json或者是html界面,也就是说无论是界面访问还是Postman客户端访问都会返回Json数据。

// 异常处理器
@ControllerAdvice
public class MyExceptionHandler {

    @ResponseBody
    @ExceptionHandler(UserNotExitException.class)
    public Map<String, Object> handleException(Exception e){
        Map<String ,Object> map = new HashMap<>();
        map.put("code","user.notExist");
        map.put("message",e.getMessage());

        return map;
    }
}

所以转发到/error来实现自适应的效果

    @ExceptionHandler(UserNotExitException.class)
    public String  handleException(Exception e,
                                   HttpServletRequest request){

        Map<String ,Object> map = new HashMap<>();

//        传入自己的异常代码
        request.setAttribute("javax.servlet.error.status_code",500);
        map.put("code","user.notExist");
        map.put("message",e.getMessage());

        return "forward:error";
    }

上面的方法并不会携带自己定制的数据;
在出现错误时响应出去的数据是由getErrorAttribbutes得到的,所以解决方法是:

  1. 编写一个ErrorController的实现类(或者是AbstractErrorController 的子类)放在容器中;
  2. 界面上和Json中的数据都是由errorAtttibutes.getErrorbutes得到的

final:
修改上方的异常处理器:

// 异常处理器
@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(UserNotExitException.class)
    public String  handleException(Exception e,
                                   HttpServletRequest request){

        Map<String ,Object> map = new HashMap<>();

//        传入自己的异常代码
        request.setAttribute("javax.servlet.error.status_code",500);
        map.put("code","user.notExist");
        map.put("message",e.getMessage());

        request.setAttribute("ext",map);

        return "forward:/error";
    }
}

新增自定义错误信息:

//给容器中添加自己定义的错误信息
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {


//    返回的map就是界面和Json能获取的所有数据
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
        map.put("company","jm");

//        异常处理器中携带的数据
        Map<String ,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext", 0);
        map.put("ext",ext);
        return map;
    }
}

最终实现了:返回自适应html和Json,以及自定义错误信息。

6. 嵌入式Servlet容器

SpringBoot使用的是嵌入式的servlet,Tomact实际上也是一个Servlet。

6.1修改Servlet容器的相关配置

  1. 修改和server有关的配置(application.properties):
server.prot=8080

#修改Servlet容器设置
server.xxx

#修改Tomcat配置
server.tomcat.xxx
  1. 编写一个EmbeddedServlletContainerCustomizer(在SpringBoot2.x中替换为WebServerFactoryCustomizer):嵌入式Servlet容器的定制器:

在自己的配置中添加:

    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
//            自定义嵌入式Servlet
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                factory.setPort(8081);
            }
        };
    }

6.2 注册servlet三大组建(Servlet,Filet,Listener)

6.2.1 注册Servlet
  @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
        return servletRegistrationBean;
    }
6.2.2 注册Filter
    @Bean
    public FilterRegistrationBean    myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
//        设置拦截器
        filterRegistrationBean.setFilter(new MyFilter());
//        设置拦截路径
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
        return filterRegistrationBean;
    }

6.2.3 注册Listener
 @Bean
    public ServletListenerRegistrationBean    myListener(){
        ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean(new MyListener());
        return registrationBean;
    }
6.2.4 使用其它的嵌入式Servlet容器

Jetty(长连接:聊天)
Undertw(不支持Jsp)

将web依赖中的Tomcat依赖排除再引入想要切换的依赖就行

undertow:

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

Jetty:

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

笔记总结自:B站BV1Et411Y7tQ27~48

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值