zoukankan      html  css  js  c++  java
  • Spring Boot入门(二)开发web应用

    Web开发

    Spring Boot Web 开发非常的简单,其中包括常用的 json 输出、filters、property、log 等

    返回json

    在控制器上添加@RestController

    Spring Boot默认类中的方法都会以 json 的格式返回

    @RestController
    public class HelloController {
        @RequestMapping("/getUser")
        public User getUser() {
            User user = new User();
            user.setUser("张三");
            return user;
        }
    }
    

    User类

    package com.example.demo.model;
    
    import lombok.Data;
    
    @Data
    public class User {
        private String User;
    }
    
    

    @Data是lombok的注解用于生成get、set方法

    引用如下

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    

    访问localhost:8080/getUser

    {"user":"张三"}

    如果需要使用页面开发只要使用@Controller注解即可

    @RestController等同于

    @Controller
    @ResponseBody
    public class HelloController {
    }
    

    自定义Filter

    我们常常在项目中会使用 filters 用于录调用日志、排除有 XSS 威胁的字符、执行权限验证等等。Spring Boot 自动添加了 OrderedCharacterEncodingFilter 和 HiddenHttpMethodFilter,并且我们可以自定义 Filter。

    @Configuration注解拦截

    两个步骤:

    1. 实现 Filter 接口,实现 Filter 方法
    2. 添加@Configuration 注解,将自定义Filter加入过滤链
    package com.example.demo.filter;
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    public class MyFilter implements Filter {
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
                throws IOException, ServletException {
            // TODO Auto-generated method stub
            HttpServletRequest request = (HttpServletRequest) srequest;
            System.out.println("this is MyFilter,url :"+request.getRequestURI());
            filterChain.doFilter(srequest, sresponse);
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
        }
    }
    
    
    package com.example.demo.config;
    
    import com.example.demo.filter.MyFilter;
    import org.apache.catalina.filters.RemoteIpFilter;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class WebConfiguration {
        @Bean
        public RemoteIpFilter remoteIpFilter() {
            return new RemoteIpFilter();
        }
    
        @Bean
        public FilterRegistrationBean testFilterRegistration() {
    
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new MyFilter());
            registration.addUrlPatterns("/*");
            registration.addInitParameter("paramName", "paramValue");
            registration.setName("MyFilter");
            registration.setOrder(1);
            return registration;
        }
    }
    

    运行后访问localhost:8080/getUser 控制台打印

    this is MyFilter,url :/getUser
    

    @WebFilter + @ServletComponentScan注解拦截

    在MyFilter类中添加@WebFilter(urlPatterns = "/*", filterName = "reqResFilter")注解

    package com.example.demo.filter;
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    @WebFilter(urlPatterns = "/*", filterName = "reqResFilter")
    public class MyFilter implements Filter {
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
                throws IOException, ServletException {
            // TODO Auto-generated method stub
            HttpServletRequest request = (HttpServletRequest) srequest;
            System.out.println("this is MyFilter,url :"+request.getRequestURI());
            filterChain.doFilter(srequest, sresponse);
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
        }
    }
    
    

    在Spring Boot启动类添加@ServletComponentScan

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

    运行后访问localhost:8080/getUser 控制台打印

    this is MyFilter,url :/getUser
    

    自定义配置

    在 Web 开发的过程中,我经常需要自定义一些配置文件,如何使用呢

    配置application.properties

    resources-> application.properties 中

    config.title="配置标题"
    config.description="标题描述"
    

    自定义配置类

    package com.example.demo.config;
    
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    @Data
    public class ConfigProperties {
        @Value("${config.title}")
        private String title;
        @Value("${config.description}")
        private String description;
    }
    
    

    重新修改下HelloWorldController文件

    package com.example.demo.controller;
    
    import com.example.demo.config.ConfigProperties;
    import com.example.demo.model.User;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @Data
    public class HelloWorldController {
    
        @Autowired
        private ConfigProperties config;
    
        @RequestMapping("/getUser")
        public User getUser() {
            User user = new User();
            user.setUser(config.getTitle()+config.getDescription());
            return user;
        }
    }
    
    

    重新启动

    访问localhost:8080/getUser

    输出

    {"user":"\"配置标题\"\"标题描述\""}
    

    配置文件乱码

    1. 设置 File Encodings的Transparent native-to-ascii conversion为true,具体步骤如下:依次点击

      File -> Settings -> Editor -> File Encodings

      将Properties Files (*.properties)下的Default encoding for properties files设置为UTF-8,将Transparent native-to-ascii conversion前的勾选上

    2 .配置完成后,一定要 重新重新重新 新建一个application.properties

    使用yml

    删除application.properties 文件

    新建application.yml文件

    config:
      title: "配置标题"
      description: "标题描述"
    

    重启

    访问localhost:8080/getUser

    输出

    {"user":"配置标题标题描述"}
    

    Spring Boot Rest API

    REST介绍

    REST代表Representational State Transfer. 是一种架构风格,设计风格而不是标准,可用于设计Web服务,可以从各种客户端使用.

    基于REST的基本设计,其是根据一组动词来控制的操作

    • 创建操作:应使用HTTP POST
    • 查询操作:应使用HTTP GET
    • 更新操作:应使用HTTP PUT
    • 删除操作:应使用HTTP DELETE

    作为REST服务开发人员或客户端,您应该遵守上述标准。

    新建HomeController

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeController {
    
        @RequestMapping(method = RequestMethod.GET)
        public String Get(){
            return "get";
        }
        @RequestMapping(method = RequestMethod.POST)
        public String insert(){
            return "insert";
        }
        @RequestMapping(method = RequestMethod.PUT)
        public String update(){
            return "update";
        }
        @RequestMapping(method = RequestMethod.DELETE)
        public String delete(){
            return "delete";
        }
    }
    
    

    通过POSTMAN访问

    localhost:8080/home

    也可以通过指定的注解@GetMapping@PostMapping@PutMapping@DeleteMapping指定不同的请求方式与上面的方法相同

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    public class HomeController {
    
        @GetMapping("/home")
        public String Get(){
            return "get";
        }
        @PostMapping("/home")
        public String insert(){
            return "insert";
        }
        @PutMapping("/home")
        public String update(){
            return "update";
        }
        @DeleteMapping("/home")
        public String delete(){
            return "delete";
        }
    }
    

    Log

    使用自带日志Slf4j

    log4j2 漏洞解析 - 池的巧克力 - 博客园 (cnblogs.com)

    Spring Boot 版本不要低于2.5.8

    org.apache.logging.log4j > 2.15

    如果你的Spring Boot 版本低于2.5.8

    使用的是父 POM,则可以设置以下属性:log4j2.version

    <properties>
        <log4j2.version>2.17.0</log4j2.version>
    </properties>
    

    如果您没有父级,而是导入 BOM 表,则需要使用一个部分:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-bom</artifactId>
                <version>2.17.0</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    或者参考这里:Log4J2 Vulnerability and Spring Boot

    package com.example.demo.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    @Slf4j
    @RestController
    public class HomeController {
    
        @GetMapping("/home")
        public String Get(){
            log.info("日志记录");
            return "get";
        }
        @PostMapping("/home")
        public String insert(){
            return "insert";
        }
        @PutMapping("/home")
        public String update(){
            return "update";
        }
        @DeleteMapping("/home")
        public String delete(){
            return "delete";
        }
    }
    
    

    如果没有配置文件就只在控制台输出

    2021-12-22 15:50:56.745  INFO 34316 --- [nio-8080-exec-1] c.e.demo.controller.HomeController       : 日志记录
    

    默认情况下,Spring Boot 仅记录到控制台,不写入日志文件。如果要写入除控制台输出之外的日志文件,则需要设置 属性

    在application.yml文件中

    logging:
      file:
        name: my.log
    

    然后在根目录查看生成的文件

    查看更多信息核心特性 (spring.io)

    数据库操作(MyBatis)

    如果你不会使用MyBatis请查看MyBatis(一)MyBatis初识 - 青杉 - 博客园 (cnblogs.com)

    引入依赖

    <!--引入 mybatis-spring-boot-starter 的依赖-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.3</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.27</version>
    </dependency>
    

    配置 MyBatis

    在 Spring Boot 的配置文件(application.properties/yml)中对 MyBatis 进行配置,例如指定 mapper.xml 的位置、实体类的位置、是否开启驼峰命名法等等,示例代码如下。

    mybatis:
      # 指定 mapper.xml 的位置
      mapper-locations: classpath:mapper/*.xml
      #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
      type-aliases-package: com.example.demo.mapper
      configuration:
        #默认开启驼峰命名法,可以不用设置该属性
        map-underscore-to-camel-case: true
    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/jdbc_test?useUnicode=true&characterEncoding=utf8&useSSL=false
        username: root
        password: 123456
        driver-class-name: "com.mysql.cj.jdbc.Driver"
    

    注意:使用 MyBatis 时,必须配置数据源信息,例如数据库 URL、数据库用户型、数据库密码和数据库驱动等。

    Sql语句

    CREATE DATABASE IF NOT EXISTS `jdbc_test`;
    
    DROP TABLE IF EXISTS `blog`;
    CREATE TABLE `blog` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `blog_title` varchar(20),
      `desc` varchar(300),
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB;
    

    创建实体类

    package com.example.demo.entity;
    
    import lombok.Data;
    
    @Data
    public class Blog {
        private int id;
        private String blogTitle;
        private String desc;
    }
    
    

    创建 Mapper 接口

    package com.example.demo.mapper;
    
    import com.example.demo.entity.Blog;
    import org.apache.ibatis.annotations.Mapper;
    
    import java.util.List;
    
    @Mapper
    public interface BlogMapper {
        int insert(Blog blog);
        int delete(int id);
        int update(Blog blog);
        List<Blog> getAll();
    
    }
    
    

    创建 Mapper 映射文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.demo.mapper.BlogMapper">
        <resultMap id="blogMap" type="com.example.demo.entity.Blog">
            <id property="id" column="id" />
            <result property="blogTitle" column="blog_title"/>
            <result property="desc" column="desc"/>
        </resultMap>
        <select id="getAll" resultMap="blogMap">
            select * from Blog
        </select>
        <insert id="insert">
            insert into Blog(blog_title,`desc`) value (#{blogTitle},#{desc})
        </insert>
        <update id="update">
            update Blog set blog_title=#{blogTitle} where id=#{id}
        </update>
        <update id="delete">
            delete from Blog where id=#{id}
        </update>
    </mapper>
    

    当 mapper 接口较多时,我们可以在 Spring Boot 主启动类上使用 @MapperScan 注解扫描指定包下的 mapper 接口,而不再需要在每个 mapper 接口上都标注 @Mapper 注解。

    创建BlogController控制器

    package com.example.demo.controller;
    
    import com.example.demo.entity.Blog;
    import com.example.demo.mapper.BlogMapper;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @RestController
    @Data
    public class BlogController {
    
        @Resource
        private BlogMapper blogMapper;
    
        @GetMapping("/blog")
        public List<Blog> GetAll(){
            return blogMapper.getAll();
        }
        @PostMapping("/blog")
        public int insert(@RequestBody Blog blog){
            return blogMapper.insert(blog);
        }
        @PutMapping("/blog")
        public int update(@RequestBody Blog blog){
            return blogMapper.update(blog);
        }
        @DeleteMapping("/blog/{id}")
        public int delete(@PathVariable int id){
            return blogMapper.delete(id);
        }
    
    }
    
    

    使用postMan测试

    事务

    在方法上@Transactional

    如下

    @PostMapping("/blog")
    @ApiOperation(value = "添加博客")
    @Transactional
    public int insert(@RequestBody Blog blog){
        blogMapper.insert(blog);
        int i = 1/0;
        return blogMapper.insert(blog);
    }
    

    Spring Boot全局异常处理

    package com.example.demo.filter;
    
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Slf4j
    @ControllerAdvice
    public class GlobalExceptionHander {
        @ResponseBody
        @ExceptionHandler(value =Exception.class)
        public String handleControllerException(HttpServletRequest request, Exception ex) {
            log.error("发生错误:",ex);
            return ex.getMessage();
        }
    }
    
    

    Swagger

    springfox/springfox:使用Spring构建的API的自动JSON API文档 (github.com)

    SpringFox by springfox

    1.引入依赖

    <!--引入 swagger 的依赖-->
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-boot-starter</artifactId>
       <version>3.0.0</version>
    </dependency>
    

    问题

    如果出现以下错误

    org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
    

    这是因为Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。

    需要添加以下配置

    spring:
      mvc:
        pathmatch:
          matching-strategy: ant_path_matcher
    

    2. 应用主类增加注解@EnableOpenApi

    @EnableOpenApi
    @SpringBootApplication
    public class DemoApplication {
     
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    

    3.配置一些接口例子

    @Api(tags = "博客管理")
    @RestController
    @Data
    public class BlogController {
    
        @Resource
        private BlogMapper blogMapper;
    
        @ApiOperation(value = "获取所有博客")
        @GetMapping("/blog")
        public List<Blog> GetAll(){
            return blogMapper.getAll();
        }
        @PostMapping("/blog")
        @ApiOperation(value = "添加博客")
        public int insert(@RequestBody Blog blog){
            return blogMapper.insert(blog);
        }
        @PutMapping("/blog")
        @ApiOperation(value = "修改博客")
        public int update(@RequestBody Blog blog){
            return blogMapper.update(blog);
        }
        @DeleteMapping("/blog/{id}")
        @ApiOperation(value = "删除博客")
        public int delete(@PathVariable int id){
            return blogMapper.delete(id);
        }
    
    }
    
    package com.example.demo.entity;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    @ApiModel(description = "博客")
    @Data
    public class Blog {
        @ApiModelProperty("id")
        private int id;
        @ApiModelProperty("博客标题")
        private String blogTitle;
        @ApiModelProperty("描述")
        private String desc;
    }
    
    

    4.启动

    启动应用!访问swagger页面:http://localhost:8080/swagger-ui/index.html

    模型验证

    引入

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

    使用

    import lombok.Data;
    import org.hibernate.validator.constraints.Length;
    
    import javax.validation.constraints.NotEmpty;
    
    
    @Data
    public class UserDto {
        @Length(min = 6,max = 18,message = "password长度必须位于6到18之间")
        private String password;
        @NotEmpty(message = "请填写手机号")
        private String mobile;
    }
    
    /**
     * 类注解
     */
    @RestController
    @RequestMapping("test")
    public class TestController {
        @RequestMapping(value = "/login",method = RequestMethod.POST)
        public UserDto Test(@Validated UserDto user){
            return u;
        }
    }
    

    更多: Spring MVC 模型验证 - 青杉 - 博客园 (cnblogs.com)

  • 相关阅读:
    [读书笔记]SQLSERVER企业级平台管理实践读书笔记--从等待事件判断性能瓶颈
    Docker machine学习
    不同数据库连接字符串的网站
    Windows 可以操纵linux内文件,与本地一致的工具
    OpenSSH 安全漏洞(CVE-2021-28041)修复(升级OpenSSH至最新版本(8.6p1))
    PostgreSQL
    firewalld添加/删除服务service,端口port
    PostgreSQL 序列操作
    PostgreSQL/pgsql 为表添加列/ 判断列存不存在再添加列
    Windows10中Power Shell(x64)出现“无法加载 PSReadline 模块。控制台在未使用 PSReadline 的情况下运行。”的解决办法
  • 原文地址:https://www.cnblogs.com/qs315/p/15726005.html
Copyright © 2011-2022 走看看