• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JavaSpringBoot应用展示

武飞扬头像
wannatolive
帮助1

SpringBoot应用简单示例

HelloWorld

搭建项目

学新通
File -> new project 选择springboot项目初始化。

学新通
学新通
选择项目默认依赖。

学新通

在项目中建一个controller,代码如下:


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * hello world测试类
 * @author Alone
 */
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String Hello() {
        return "Hello,world!";
    }
}


学新通

输出结果:
学新通

@ResponseBody的作用

将方法的返回值,以特定的格式写入到response的body区域,进而将数据返回给客户端。当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。

@RequestMapping、@ResponseBody 等这些注解是干什么的? - 果真真的回答 - 知乎

前置知识-SpringMVC请求流程

DispatcherServlet#doDispatch

@ComponentScan排除扫描bean

学新通

SpringBoot集成日志

SpringBoot日志初始化原理

学新通

有个loggingApplicationListener的监听器,监听了spring的事件,读取了spring容器中的日志配置,进行了日志的初始化。
(springboot-actuator可以实现动态调整日志级别,待研究)

消息转换器

to be continue

拦截器

拦截器是一种动态拦截方法调用的机制。可以在指定方法前后执行预先设定的代码以及阻止方法调用。

拦截器的实现需要实现HandlerInterceptor 接口:

/**
 * 拦截器测试
 * @author Alone
 */
@Component
public class InterceptConfiguration implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        // 此处返回false导致后面不再执行
        return false;
    }

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

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

将拦截器添加入SpringMVC的配置类:

/**
 * @author Alone
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private InterceptConfiguration interceptConfiguration;

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

学新通
默认是返回true。

学新通
HandlerInterceptor 中三个方法的作用:

  1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) : 方法在请求处理之前调用,在这个方法中进行一些前置预处理或初始化操作,也可以决定是否终止请求。当该方法返回false时,后续的interceptor和controller都不会执行。拦截器可以注册多个,调用时依据声明顺序依次执行。
    handler 参数本质上是一个方法对象,有了它就可以操作原始执行的方法。
  2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) : 在当前请求处理之后,DispatcherServlet进行视图渲染之前调用。此时可以对controller处理之后的modelAndView对象进行操作。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) : 该方法在整个请求结束后进行调用,主要用于清理资源。

多拦截器的执行顺序:

学新通

过滤器

to be continue

操作数据库

Spring Data Jpa

  1. 引入依赖 pom.xml:
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

配置文件application.yml:

spring:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
  datasource:
    url: jdbc:mysql://localhost:3306/gotest?useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 我是密码

spring.jpa.hibernate.ddl-auto 属性的选项说明:

  • create : 无论数据是否改变,每次hibernate 加载时都删除上一次生成的表
  • create-drop : 每次加载hibernate 时都根据实体类生成表,但是sessionFactory一关闭,表就自动删除。
  • update : 每次加载hibernate时根据model类会自动更新表的结构,不存在则新建。不会删除旧数据。
  • validate : 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
  • none : 不做任何操作

实体类:

package com.alone.simpleusage.database.datajpa.entity;

import lombok.Data;

import javax.persistence.*;

/**
 * 学生实体类
 * @Entity 表示这是一个实体类
 * @Table 定义数据库表名,jpa在操作的时候会先去寻找这张表,没有这张表的话就创建
 *
 * @author Alone
 */
@Data
@Entity
@Table(name = "student")
public class Student {

    /**
     * @Id 表示这是主键
     * @GeneratedValue 主键生成策略
     * @Column 配置属性和数据库字段的对应
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer urid;

    @Column(name = "code")
    private String code;

    @Column
    private String name;
}

学新通

dao接口:

package com.alone.simpleusage.database.datajpa.dao;

import com.alone.simpleusage.database.datajpa.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, Integer> {
}

运行测试:

@SpringBootTest
public class RepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void testInsert() {
        Student student = new Student();
        student.setCode("1");
        student.setName("顶不住了");
        studentRepository.save(student);
    }
}

运行结果:

学新通

Spring JPA实现的默认方法:
学新通
Spring jpa 动态查询:

public interface StudentRepository extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
}
@Test
    public void testQuery() {
        List<Student> userList = studentRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            // 定义集合,用于存放动态查询条件
            List<Predicate> predicateList = Lists.newArrayList();
            predicateList.add(criteriaBuilder.like(root.get("code").as(String.class), "%1%"));
            predicateList.add(criteriaBuilder.like(root.get("name").as(String.class), "%顶%"));
            return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
        }));
        userList.forEach(System.out::println);
    }

输出结果:
学新通
多表联查:
to be continue

分页查询:

@Test
    public void testPageQuery() {
        // 构造查询条件
        Specification<Student> spec = new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return null;
            }
        };
        // 分页查询接口
        PageRequest pageRequest = PageRequest.of(0, 1);
        Page<Student> students = studentRepository.findAll(spec, pageRequest);
        System.out.println("查询总页数:"   students.getTotalPages());
        System.out.println("查询总记录数:"   students.getTotalElements());
        System.out.println("数据集合列表:"   students.getContent());
    }
学新通

结果:
学新通
排序查询:

@Test
    public void testSortQuery() {
        Sort sort = Sort.by(Sort.Direction.DESC, "urid");
        Specification<Student> spec = new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return null;
            }
        };
        List<Student> studentList = studentRepository.findAll(spec, sort);
        for (Student student : studentList) {
            System.out.println(student);
        }
    }

学新通

Druid数据源

  1. 添加依赖引入druid数据源:
<!-- spring jdbc 操作模版 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 引入druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.4</version>
        </dependency>
  1. 编写配置文件:
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/gotest?useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 密码
    type: com.alibaba.druid.pool.DruidDataSource
  1. 编写配置bean:
/**
 * Druid数据源配置类
 * @author Alone
 */
@Configuration
public class DruidConfig {

    /**
     * 配置绑定
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druid() {
        return new DruidDataSource();
    }
}
学新通

此处的前缀prefix要和application.yml中的前缀对应,不然会报java.sql.SQLException: url not set 的异常。
且该注解一定要标在对应bean上。

  1. 测试获取数据源
@Test
    public void testGetDruidDataBase() throws SQLException {
        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }

Mybatis-Plus

  1. 引入依赖:
<!-- mybatis-plus 依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
  1. 配置文件:
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启sql语句打印
  1. 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Long managerId;
    private LocalDateTime createTime;
}

此处简单说一下LocalDateTime相较于Date的优点:

  • Date类型的打印出的日期可读性差
  • Date使用SimpleDateFormat 进行格式化,该对象线程不安全
  • Date日期处理麻烦,getYear() getDay() 等方法均已被弃用
  1. 定义mapper接口
public interface UserMapper extends BaseMapper<User> {
}
  1. 启动类添加mapperscan注解
@SpringBootApplication
@MapperScan("com.alone.simpleusage.database.mpp")
public class SimpleusageApplication {

    public static void main(String[] args) {
        SpringApplication.run(SimpleusageApplication.class, args);
    }

}
  1. 测试
@Test
    public void testUserMapper() {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        User user = new User(6L, "test", 10, "123456@163.com", null, LocalDateTime.parse("2022-11-08 15:44:00", df));
        userMapper.insert(user);
    }

事务处理

【Java】Spring事务相关笔记

操作缓存

AOP

相关概念

AOP(Aspect Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。主要用于分离系统的业务逻辑和系统服务。

通知:指切面要完成的工作,定义了切面是什么以及何时使用。

共有5种类型:

  • 前置通知(Before):在目标方法被调用之前调用通知功能
  • 后置通知(After):在目标方法完成之后调用通知,此时不关心方法的输出结果是什么
  • 返回通知(After-returning):在目标方法成功执行之后调用通知
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
    学新通
    连接点:应用在执行时能够插入切面的位置
    切点:切面执行的位置
    切面:切点和通知的结合
    引入:在不修改现有类的基础上,向类中添加新方法和新属性。
    织入:把切面应用到目标对象并创建新的代理对象的过程。可以在编译期(此时需要特殊的编译器,例如AspectJ),类加载期(切面在目标类加载到JVM时被织入,需要特殊的类加载器),运行期(应用运行的某一时刻,例如Spring AOP)织入切面。

栗子

springboot切面实现打印当前系统时间:

pom.xml:

<!-- aop依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

切面类:

package com.alone.simpleusage.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;

/**
 * 切面类
 * @author Alone
 */
@Aspect
@Component
@Slf4j
public class SysOutTimeAspect {


    /**
     * 切入点方法
     */
    @Pointcut("execution(public * com.alone.simpleusage.aop.controller.*.*(..))")
    public void printTime() {

    }

    /**
     * 前置通知
     * 这里的方法名和入参都不能写错,不然会进不去需要被增强的方法
     * @param joinPoint
     */
    @Before("printTime()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("开始打印");
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info(df.format(System.currentTimeMillis()));

    }
}

学新通

测试类:

package com.alone.simpleusage.aop.controller;

import org.springframework.web.bind.annotation.*;

/**
 * 切面测试controller
 * @author Alone
 */
@RestController
@RequestMapping("/aoptest")
public class AopController {

    @RequestMapping("/hello")
    public String hello(@RequestParam(value = "name", required = false) String name) {
        System.out.println("进入hello方法");
        return "hello"   name;
    }
}

学新通

结果:

学新通
学新通

工作流程

  1. Spring容器启动
  2. 读取所有切面配置中的切入点,没有被切面引入的切点不会被加载。
  3. 初始化bean:判定bean对应的类中的方法是否匹配到任意切入点,如果匹配失败,则创建对象,匹配成功则创建原始对象的代理对象
  4. 获取bean执行方法:如果获取到的是bean对象自身则调用方法并执行,如果获取到代理对象则根据代理对象的运行模式运行原始方法与增强的内容。

切入点表达式书写规则

以类名描述:
execution (访问修饰符 返回值 包名.类/接口名.方法名 (参数) 异常名)

通配符:
* :单个独立的任意符号
.. : 多个连续的任意符号
: 匹配子类

注意事项

如果是环绕通知,被增强方法的返回值是void时执行proceedingJoinPoint.proceed() 后得到的返回值是null
学新通

事件发布

主要用于操作解耦。

事件定义:

package com.alone.simpleusage.event;

import org.springframework.context.ApplicationEvent;

/**
 * 事件定义
 * @author Alone
 */
public class MailEvent extends ApplicationEvent {

    private String message;

    public MailEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String sendMail() {
        return message;
    }
}

学新通

事件发布:

package com.alone.simpleusage.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

/**
 * 事件发布
 * @author Alone
 */
@Component
@Slf4j
public class MailEventPublisher {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void publish(String message) {
        log.info("开始发送");
        MailEvent mailEvent = new MailEvent(this, message);
        applicationEventPublisher.publishEvent(mailEvent);
    }
}

学新通

事件监听:

package com.alone.simpleusage.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.time.LocalTime;

/**
 * 事件监听
 * @author Alone
 */
@Component
@Slf4j
public class MailEventListener {

    @EventListener
    public void receiveMail(MailEvent mailEvent) {
        String message = mailEvent.sendMail();
        log.info("receive message: "   message   "time: "   LocalTime.now());
    }
}

学新通

测试:

package com.alone.simpleusage.event;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class EventTest {

    @Resource
    private MailEventPublisher sendEmailEventPublisher;

    @Test
    public void publish() {
        sendEmailEventPublisher.publish("hello world");
    }
}

学新通

整合Quartz

  1. 导入坐标
  2. 定义具体要执行的任务
  3. 定义工作明细与触发器,并绑定对应关系

参考资料

  1. springboot动态调整日志级别
  2. 玩转 Spring Boot 系列案例源码
  3. 优雅的使用spring boot: 消息转换器的介绍与使用
  4. SpringBoot实现过滤器、拦截器与切片
  5. 黑马程序员2022新版SSM框架教程
  6. SpringBoot图文教程12—SpringData Jpa的基本使用
  7. Springboot 系列(九)使用 Spring JDBC 和 Druid 数据源监控
  8. mybatis plus 看这篇就够了,一发入魂
  9. 学会了MybatisPlus,代码开发效率提高了10倍!
  10. Spring Boot (五): Redis缓存使用姿势盘点
  11. Spring boot学习(六)Spring boot实现AOP记录操作日志
  12. SpringBoot—集成AOP详解(面向切面编程Aspect)
  13. Spring框架中的事件订阅发布
  14. Spring入门(十):Spring AOP使用讲解

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfkjfec
系列文章
更多 icon
同类精品
更多 icon
继续加载