springboot原理实战(14)–springbootweb

目录:

本文章的大纲如下:springboot原理实战(14)--springbootweb

第一部分:

一、请求method

springboot的请求注解@RequestMapping(value = "/user/home",method= RequestMethod.GET)spring4.3以后可以使用: @GetMapping("/user/home2"),@PostMapping("/user/create")等语义化表示get,post等请求方法。springboot原理实战(14)--springbootweb

二、传递参数的3种方式

1.RequestParam

@RequestParam 默认必填,可以设置非必填,和默认值:

/**
     *  @RequestParam 注解默认是参数必须提供值
     * @param username
     * @param password
     * @return
     */

    @PostMapping("/user/create")
    @ResponseBody
    public String create(@RequestParam(value = "username",defaultValue = "admin") String username, @RequestParam(value="password",required = false) String password){
        return "user create, username=" + username + ",password="+password;
    }

2.url方式 @PathVariable

 /**
     * 获取url的方式/user/1 ,/user/2
     * @param id
     * @return
     */

    @GetMapping("/user/{id}")
    @ResponseBody
    public String display(@PathVariable("id") String id){
        return "user display is=" + id;
    }

3.HttpServletRequest方式

@ResponseBody
    @GetMapping("/user/ip")
    public String edit(HttpServletRequest req){
        return "user edit " + req.getRemoteHost();
    }

三、@RestController

这个注解相当于@Controller+@RequestBody,用在视图访问层,表示当前controller的方法的返回值并可以直接用于body测试.返回json格式数据:springboot原理实战(14)--springbootweb

四、springboot的数据渲染到jsp页面

需要的步骤:

1.配置文件:

application.properties加入2个配置项,执行页面路径和后缀

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

2.加入 tomcat-embed-jasper的依赖

pom.xml中:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
<!--  <version>9.0.27</version>-->
</dependency>
<!--servlet依赖jar-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
</dependency>
<!--Jstl标签依赖的jar包start-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>

build下加入resoures

        <resources>
<!--            <resource>-->
<!--                <directory>src/main/java</directory>-->
<!--                <includes>-->
<!--                    <include>**/*.xml</include>-->
<!--                </includes>-->
<!--            </resource>-->
<!--            <resource>-->
<!--                <directory>src/main/resources</directory>-->
<!--                <includes>-->
<!--                    <include>**/
*.*</include>-->
<!--                </includes>-->
<!--            </resource>-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

3.测试:

@Controller
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password) {
        if (username.equals(password)) {
            return "ok";
        }
        return "fail";
    }

    /**
     * 给jsp传参数,类似req.setAttribute
     * @param model
     * @return
     */

    @GetMapping("/login")
    public String loginIndex(Model model){
        model.addAttribute("username""root");
        return "login";
    }
}

login.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <h1>this is login page</h1>
 <p>username is ${username}</p>
</body>
</html>

运行入口函数

@SpringBootApplication
public class Demo11Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Demo11Application.classargs);
    }

}

运行结果,显示已经数据已经渲染到jsp页面:springboot原理实战(14)--springbootweb

五、springboot渲染数据到freemarker页面:

在springboot中使用freemarker的步骤

1. 在pom.xml里面加入依赖

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

2.配置文件修改freemarker的位置和后缀

看配置信息可以看源码: FreeMarkerProperties:springboot原理实战(14)--springbootweb我们在application.properties中修改配置信息:

spring.freemarker.templateLoaderPath=classpath:/ftl/
spring.freemarker.suffix=.ftl

3.测试:

@Controller
public class AccountController {

    @RequestMapping("/reg")
    public String req(Model model){
        model.addAttribute("username""root");
        return "reg";
    }
}

页面代码:springboot原理实战(14)--springbootweb运行入口函数:

@SpringBootApplication
public class Demo11Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Demo11Application.classargs);
    }

}

查看页面,显示已经渲染到HTML页面:springboot原理实战(14)--springbootweb

六、更换web容器

pringboot 容器默认使用的是tomcat作为外部容器, 可以更换为jetty。具体操作如下:

1.排除tomcat,加入jetty的依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
           <!--  排除tomcat-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

2.测试:

运行入口函数:

@SpringBootApplication
public class Demo11Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Demo11Application.classargs);
    }

}

运行结果,看打印结果,已显示为jetty:springboot原理实战(14)--springbootweb

源码地址:https://github.com/hufanglei/springboot-v-study/tree/springboot-web1


第二部分

一、请求静态资源:

1. 放在webapp下 加resources.xml 可以访问到

做个案例,测试下:

  • 在webapp下准备一个图片和一个user.htmlspringboot原理实战(14)--springbootweb
  • pom上加入资源
 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <!--注意此次必须要放在此目录下才能被访问到 -->
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/**</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>

    </build>
  • 入口函数启动:
@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

  • 查看效果,显示图片和页面都可以访问到:springboot原理实战(14)--springbootweb

2. springboot默认的静态资源的路径是:

  • “classpath:/META-INF/resources/”,
  • “classpath:/resources/”,
  • “classpath:/static/”,
  • “classpath:/public/” };

我们可以在ResourceProperties源码中找到这个原因:springboot原理实战(14)--springbootweb在public下准备个文件看下能否访问到:springboot原理实战(14)--springbootweb运行入口函数:看下页面,显示已经访问到public下的html页面和css。springboot原理实战(14)--springbootweb

3.可以通过spring.resources.static-locations 配置项修改默认静态资源路径

试一试:我们指定html文件下为我们的默认静态资源路径,并准备个login.html,看下能否访问:springboot原理实战(14)--springbootwebspringboot原理实战(14)--springbootweb运行,看下页面效果:springboot原理实战(14)--springbootweb结果显示已经访问到html下的页面。修改默认的静态资源路径成功。

二、sevlet,filter,listener的2种配置方式:

1.springboot如何使用servlet

有2种方式,一种是用sevlet3加入口函数注解扫码方式,一种是配置类注入servlet方式: 现在动手试试:

① 方法一:(servlet3可以使用这种方法)

  • 1)编写servlet,然后加上响应的注解@WebServlet
  • 2)需要启用@ServletComonentScan注解
@WebServlet("/user.do")
public class BookServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public BookServlet() {
        System.out.println("===servet BookServlet========");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("book servlet");
    }

}

@ServletComponentScan
@SpringBootApplication
public class Demo12Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }
}

运行入口,访问BookServlet 映射的user.do路径:springboot原理实战(14)--springbootweb说明servlet已经访问成功。

② 方法2:(servlet2.5及以下版本可以使用这种方法)

  • 1) 书写servlet无需对位映射,不用加@WebServlet注解
  • 2)书写个配置类,使用@Bean注入,注入的话,需要调用ServletRegistrationBean的构造方法。代码如下: servlet:
public class BookServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public BookServlet() {
        System.out.println("===servet BookServlet========");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("book servlet");
    }
}

配置类:

@SpringBootConfiguration
public class ServletConfigration {

    @Bean
    public ServletRegistrationBean createBookServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new BookServlet(), "/book.do");
        return servletRegistrationBean;
    }
}

入口函数

@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

启动并测试:结果显示ok:springboot原理实战(14)--springbootweb

2.springboot如何使用过滤器

使用的方式和servet差不多,一种是@WebFilter(“/*”)注解方式,另一种是也是通过配置类: 不过生成filter的类是 fileter -》 FilterRegistrationBean。

方式1通过@WebFilter(“/*”)+入口@ServletComponentScan注解实现过滤器

@WebFilter("/*")
public class LogFilter implements  Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("==LogFilter =init===");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("==LogFilter =filter ==="+ request.getRemoteHost());
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        System.out.println("=====destroy======");
    }
}

入口函数

@ServletComponentScan
@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

启动入口函数,访问刚才的servlet,看下控制台打印情况:springboot原理实战(14)--springbootweb显示过滤器已经被注入了。

方式2:配置类+注入bean,

代码:

public class EchoFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        System.out.println("spring boot web filter "+ req.getRequestURI());
        chain.doFilter(request,response);
    }
    @Override
    public void destroy() {

    }
}

配置类:

@SpringBootConfiguration
public class ServletConfigration {

    @Bean
    public FilterRegistrationBean createFilterRegistrationBean(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new EchoFilter());
        filter.setUrlPatterns(Arrays.asList("/book.do"));
        return filter;
    }

入口函数

@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

测试:springboot原理实战(14)--springbootweb

运行结果:显示过滤器已经起作用了。springboot原理实战(14)--springbootweb

3.springboot如何使用监听器

1)方式1:@WebListener+@ServletComponentScan

@WebListener
public class MyListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("StartUpListener app startup at " + LocalDateTime.now().toString());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}
@ServletComponentScan
@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

启动:springboot原理实战(14)--springbootweb

2)方式2:配置类+@bean+ServletListenerRegistrationBean构造函数注入

public class StartUpListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("StartUpListener app startup at " + LocalDateTime.now().toString());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

@SpringBootConfiguration
public class ServletConfigration {

    @Bean
    public ServletListenerRegistrationBean createServletListenerRegistrationBean(){
        ServletListenerRegistrationBean listener = new ServletListenerRegistrationBean(new StartUpListener());
        return listener;
    }
 }

@SpringBootApplication
public class Demo12Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo12Application.classargs);
    }

}

启动:springboot原理实战(14)--springbootweb源码地址:https://github.com/hufanglei/springboot-v-study/tree/demo12


第三部分

1.拦截器:

拦截器的使用步骤

①写一个拦截器,实现HandlerInterceptor接口

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LogHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("=========preHandle===============" + handler);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("=========postHandle===============" + handler);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("=========afterCompletion===============" + handler);
    }
}

  • preHandle:controller执行之前调用
  • postHandle:controller执行之后,且页面渲染之前调用
  • afterCompletion:页面渲染之后调用,一般用于资源清理操作

②写一个类,实现WebMvcConfigurer接口,重写addInterceptors方法(已经过时),并调用registry.addInterceptor把上一步的拦截器加进去

@SpringBootConfiguration
public class WebConfiguration implements WebMvcConfigurer {

//    @Override
//    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        registry.addResourceHandler("/web/**").addResourceLocations("classpath:/web/");
//    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogHandlerInterceptor());
    }
}

测试

写个controller

@RestController
public class UserController {

    @GetMapping("/user/home")
    public String home(){
        return "user home";
    }

    @GetMapping("/user/help")
    public String help()  {
        throw new IllegalArgumentException("args is empty");
    }
}

@SpringBootApplication
public class Demo13Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo13Application.classargs);
    }
}

页面测试:springboot原理实战(14)--springbootweb看下控制台:springboot原理实战(14)--springbootweb显示已经拦截controller。

2.异常处理:

1)默认异常处理逻辑ErrorMvcAutoConfiguration

当我们访问一个不存在的url时候会出现如下页面:springboot原理实战(14)--springbootweb看下ErrorMvcAutoConfiguration源码:springboot原理实战(14)--springbootwebspringboot原理实战(14)--springbootweb

排除springboot默认显示的异常页方式1:

可以看到找到就是渲染的这段代码。我们可以关闭这个默认异常页配置:springboot原理实战(14)--springbootweb看了源码再去修改applicaiton.properties

server.error.whitelabel.enabled=false

重新运行:springboot原理实战(14)--springbootweb输入一个无效的url,就没有默认的异常处理页了。

排除springboot默认显示的异常页方式2:

也可以直接在入口函数上,用exclude去排除自动注册的这个默认异常注册类:

@SpringBootApplication(exclude = ErrorMvcAutoConfiguration.class)
public class Demo13Application 
{

    public static void main(String[] args) {
        SpringApplication.run(Demo13Application.classargs);
    }
}

2).自处理异常

定义一个controller。手动抛出异常:

①在当前controller类使用@ExceptionHandler处理异常

@RestController
public class BookController {

//    @ExceptionHandler(value = FileNotFoundException.class)
    @ExceptionHandler(value = FileNotFoundException.class)
    public String error(Exception e)
{
        return "file not found exception====  " + e.getMessage();
    }

    @GetMapping("/book/error1")
    public String list() throws FileNotFoundException {
        throw new FileNotFoundException("file not found");
    }

    @GetMapping("/book/error2")
    public String error2() throws ClassNotFoundException {
        throw new ClassNotFoundException("file not found");
    }

    @GetMapping("/user/null")
    public String empty() {
        throw new NullPointerException("args is empty");
    }
}

我们看到访问list,error2,empty的方法都会抛出异常,同时定义一个处理异常的方法error:

  @ExceptionHandler(value = FileNotFoundException.class)
    public String error(Exception e)
{
        return "file not found exception====  " + e.getMessage();
    }

如果匹配到 @ExceptionHandler中value对应的异常,就可以在error方法中处理异常,或者跳转到错误页面。我们访问/user/null:springboot原理实战(14)--springbootweb因为 @GetMapping("/user/null") public String empty() { throw new NullPointerException("args is empty"); } }对应的是空指针异常,而 @ExceptionHandler(value = FileNotFoundException.class)是文件找不到的异常,所以controller没给我们处理。

然后访问@GetMapping(“/book/error1”)springboot原理实战(14)--springbootweb看到已经帮我们处理了。如果想要@ExceptionHandler当前类全部的方法,就可以扩大异常范围,改成exception.class就可了。

  @ExceptionHandler(value = Exception.class)
    public String error(Exception e)
{
        return " exception====  " + e.getMessage();
    }

②全局处理异常的2种方式:

  • a.方式1:使用ErrorPageRegistrar的接口

写一个类,实现ErrorPageRegistrar接口,实现registerErrorPages,在该方法里面,添加具体的错误处理逻辑

@Component
public class CommonErrorRegistry implements ErrorPageRegistrar {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
        ErrorPage e500 = new ErrorPage(INTERNAL_SERVER_ERROR, "/500.html");
        ErrorPage argsPage= new ErrorPage(IllegalArgumentException.class, "/args.html");
        registry.addErrorPages(e404, e500,argsPage);
    }
}
  • b.方式2:@ControllerAdvice 具体做法:

-1.写一个类,需要加上@ControllerAdvice注解 -2.写一个异常处理方法,需要加上@Exception(value=Exception.class)这个注解,在该方法上处理异常,

@ControllerAdvice
public class GloabalExceptinHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String errorHandler(Exception e)
{
       return "gloabal error  " + e.getClass().getName()+ " =="+ e.getMessage();
    }

    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public String errorHandler2(Exception e)
{
        return "gloabal error2  " + e.getClass().getName()+ " =="+ e.getMessage();
    }
}

这2种方法都可以跳转到自定义的页面,或者抛出异常。看下这个ErrorPage类的源码:springboot原理实战(14)--springbootweb可以看到,errorpage可以通过请求响应状态码控制跳转页面,可以根据具体异常控制跳转页。

演示代码git地址:https://github.com/hufanglei/springboot-v-study/tree/springbootweb3


以上就说了springbootweb的大体内容,基础springboot2的。关于请求方法参数,数据渲染到jsp页面和freemarker页面的配置方式,替换内置tomcat的方法,请求静态页面的设置,过滤器,监听器,servlet的2种注册方式,拦截器的自定义,异常处理的类上的处理,和全局处理的2种方式。


个人微信公号:怒放de每一天 。不定时推送相关文章,期待和大家一起成长!!



原文始发于微信公众号(怒放de每一天):springboot原理实战(14)–springbootweb

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/106623.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!