MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java Spring Boot的快速开发与迭代

2024-07-121.6k 阅读

Java Spring Boot的快速开发与迭代

Spring Boot简介

Spring Boot是由Pivotal团队提供的全新框架,它基于Spring框架,旨在简化Spring应用的初始搭建以及开发过程。Spring Boot致力于让开发者尽可能快地跑起来一个Spring应用并投入生产。它通过大量的自动配置,减少了开发者手动配置Spring的繁琐工作,使得开发人员能够专注于业务逻辑的实现。

例如,传统的Spring应用需要在XML文件中进行大量的配置,如配置数据源、事务管理器等。而Spring Boot通过约定大于配置的原则,只要在application.propertiesapplication.yml文件中进行简单的配置,就能自动装配相关的Bean。

快速开发基础

项目初始化

  1. 使用Spring Initializr:Spring Initializr是一个在线的项目初始化工具,网址为start.spring.io。在这个网站上,我们可以轻松地创建一个Spring Boot项目。首先,选择项目的构建工具,一般有Maven和Gradle两种选择。Maven是基于XML的项目管理工具,Gradle则结合了Ant的灵活性和Maven的约定,使用Groovy或Kotlin脚本进行配置。

假设我们选择Maven作为构建工具,接着选择Spring Boot的版本。然后,在依赖选项中添加项目所需的依赖,比如Web开发依赖spring-boot-starter-web,如果需要操作数据库,可能会添加spring-boot-starter-jdbc以及对应的数据库驱动依赖。填写好项目的基本信息,如Group、Artifact等后,点击生成项目,就会下载一个压缩包,解压后即可得到一个基本的Spring Boot项目结构。

  1. IDE集成:在IntelliJ IDEA中,也可以直接通过File -> New -> Project,然后选择Spring Initializr来创建项目,操作步骤与在线工具类似,但更加便捷,且创建完成后直接在IDE中打开项目。

目录结构

解压或创建好的Spring Boot项目,其基本目录结构如下:

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           └── myproject/
│   │               ├── MyprojectApplication.java
│   │               └── controller/
│   │                   └── HelloController.java
│   └── resources/
│       ├── application.properties
│       ├── static/
│       └── templates/
└── test/
    └── java/
        └── com/
            └── example/
                └── myproject/
                    └── MyprojectApplicationTests.java
  • src/main/java:存放Java源代码,一般按照包名分层结构组织,最顶层的包名通常与项目的Group相关。MyprojectApplication.java是Spring Boot应用的启动类,包含main方法,通过SpringApplication.run(MyprojectApplication.class, args);来启动Spring应用。
  • src/main/resources:存放资源文件,application.propertiesapplication.yml文件用于配置应用的参数,如数据库连接、服务器端口等。static目录用于存放静态资源,如CSS、JavaScript、图片等。templates目录用于存放模板文件,通常与模板引擎(如Thymeleaf)结合使用。
  • src/test/java:存放测试代码,MyprojectApplicationTests.java是一个自动生成的测试类,用于对Spring Boot应用进行基本的测试。

第一个Spring Boot应用

  1. 创建Controller:在controller包下创建HelloController.java文件,代码如下:
package com.example.myproject.controller;

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

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
}
  • @RestController注解表示这是一个RESTful风格的控制器,它结合了@Controller@ResponseBody注解的功能,意味着这个类中的方法返回的数据会直接作为HTTP响应体返回,而不会被解析为视图。
  • @GetMapping("/hello")注解表示该方法处理HTTP的GET请求,路径为/hello。当客户端访问http://localhost:8080/hello(假设应用运行在8080端口)时,会调用hello方法,并返回Hello, Spring Boot!
  1. 运行应用:可以直接在IDE中右键点击MyprojectApplication.java文件,选择Run来启动Spring Boot应用。也可以通过命令行进入项目根目录,使用mvn spring-boot:run(如果是Maven项目)或./gradlew bootRun(如果是Gradle项目)来启动应用。启动成功后,在浏览器中访问http://localhost:8080/hello,就能看到返回的Hello, Spring Boot!

深入Spring Boot开发

配置管理

  1. application.propertiesapplication.yml:Spring Boot支持两种主要的配置文件格式,即application.propertiesapplication.ymlapplication.properties是传统的键值对格式,例如:
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password

application.yml使用YAML格式,以缩进表示层级关系,更加简洁易读,例如:

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: password
  1. 配置加载顺序:Spring Boot会按照一定的顺序加载配置文件,优先级从高到低依次为:命令行参数 > 来自SPRING_APPLICATION_JSON的属性(通过环境变量或系统属性指定的JSON格式配置) > 操作系统环境变量 > JVM系统属性 > RandomValuePropertySource配置的随机值(用于生成随机数) > 应用的application.propertiesapplication.yml文件(包括不同环境的配置,如application-{profile}.properties) > 测试用的application.propertiesapplication.yml文件 > 所有@Configuration类中的@PropertySource注解加载的属性 > 默认属性。

  2. 自定义配置属性:我们可以定义自己的配置属性,并将其注入到Spring组件中。首先,创建一个配置类,例如MyConfigProperties.java

package com.example.myproject.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "myapp")
public class MyConfigProperties {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

然后在application.propertiesapplication.yml文件中添加配置:

myapp.message=This is a custom message
myapp:
  message: This is a custom message

最后,在需要使用的地方注入MyConfigProperties,比如在HelloController.java中:

package com.example.myproject.controller;

import com.example.myproject.config.MyConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired
    private MyConfigProperties myConfigProperties;

    @GetMapping("/custom")
    public String custom() {
        return myConfigProperties.getMessage();
    }
}

当访问/custom时,就会返回This is a custom message

数据访问

  1. JDBC:Spring Boot对JDBC提供了很好的支持。首先,添加spring-boot-starter-jdbc依赖以及对应的数据库驱动依赖(如mysql-connector-java)。然后,在配置文件中配置数据源。接着,可以使用JdbcTemplate来执行SQL语句。例如:
package com.example.myproject.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Map<String, Object>> getAllUsers() {
        String sql = "SELECT * FROM users";
        return jdbcTemplate.queryForList(sql);
    }
}
  1. Spring Data JPA:Spring Data JPA是基于JPA规范的一个框架,它进一步简化了数据库访问层的开发。添加spring-boot-starter-data-jpa依赖以及数据库驱动依赖。定义实体类,例如User.java
package com.example.myproject.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    // getters and setters
}

然后创建一个继承自JpaRepository的接口,例如UserRepository.java

package com.example.myproject.repository;

import com.example.myproject.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

通过这个接口,Spring Data JPA会自动为我们实现基本的CRUD操作。例如,在UserService.java中使用:

package com.example.myproject.service;

import com.example.myproject.entity.User;
import com.example.myproject.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}
  1. NoSQL数据库:Spring Boot也支持多种NoSQL数据库,如MongoDB、Redis等。以MongoDB为例,添加spring-boot-starter-data-mongodb依赖。定义MongoDB的实体类,例如Book.java
package com.example.myproject.entity;

import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "books")
public class Book {
    private String id;
    private String title;
    private String author;

    // getters and setters
}

创建BookRepository接口,继承自MongoRepository

package com.example.myproject.repository;

import com.example.myproject.entity.Book;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface BookRepository extends MongoRepository<Book, String> {
}

这样就可以方便地对MongoDB中的books集合进行操作了。

事务管理

  1. 声明式事务:Spring Boot的声明式事务管理非常方便。在Spring Boot项目中,默认已经对事务管理进行了自动配置。只需要在需要事务管理的方法或类上添加@Transactional注解即可。例如,在UserService.java中,如果有一个方法需要进行事务操作:
package com.example.myproject.service;

import com.example.myproject.entity.User;
import com.example.myproject.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void saveUserAndDoSomething(User user) {
        userRepository.save(user);
        // 假设这里还有其他可能会失败的操作
    }
}

如果在saveUserAndDoSomething方法执行过程中出现异常,整个事务会回滚,user不会被保存到数据库。

  1. 事务传播行为@Transactional注解还支持设置事务传播行为,如PROPAGATION_REQUIRED(默认值,当前有事务则加入,没有则创建新事务)、PROPAGATION_REQUIRES_NEW(总是创建新事务)、PROPAGATION_NESTED(在现有事务中创建嵌套事务)等。例如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void someMethod() {
    // 方法逻辑
}

Spring Boot的迭代开发

版本控制

  1. 使用Git:在Spring Boot项目开发过程中,使用Git进行版本控制是非常必要的。首先,在项目根目录初始化Git仓库,执行git init。然后,可以通过git add命令将文件添加到暂存区,例如git add.添加所有文件。接着使用git commit -m "Initial commit"进行提交,-m后面的内容是提交信息。

  2. 分支管理:为了更好地进行迭代开发,合理的分支管理很重要。一般会有master主分支用于稳定版本发布,develop开发分支用于日常开发。当需要开发新功能时,可以从develop分支创建功能分支,例如feature/user-login。在功能分支上进行开发,完成后合并回develop分支。当需要修复线上问题时,从master分支创建hotfix分支,修复完成后合并回masterdevelop分支。

持续集成与持续交付(CI/CD)

  1. CI工具 - Jenkins:可以使用Jenkins搭建持续集成环境。首先,在Jenkins中创建一个新的自由风格项目。配置项目的代码仓库地址,例如Git仓库地址,并添加凭证(如果仓库需要认证)。然后,配置构建步骤,对于Maven项目,可以选择执行mvn clean install命令来编译和打包项目。如果项目有单元测试,测试结果会在Jenkins中显示。

  2. CD工具 - Docker和Kubernetes:将Spring Boot应用打包成Docker镜像,然后使用Kubernetes进行容器编排和部署。编写Dockerfile文件,例如:

FROM openjdk:11
COPY target/myproject-0.0.1-SNAPSHOT.jar myproject.jar
ENTRYPOINT ["java", "-jar", "/myproject.jar"]

在项目根目录执行docker build -t myproject:latest.来构建Docker镜像。然后,编写Kubernetes的部署文件,如deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myproject-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myproject
  template:
    metadata:
      labels:
        app: myproject
    spec:
      containers:
      - name: myproject
        image: myproject:latest
        ports:
        - containerPort: 8080

通过kubectl apply -f deployment.yml来部署应用到Kubernetes集群中。这样,当代码更新并通过CI流程后,可以自动更新Docker镜像,并通过CD流程部署到生产环境。

代码优化与重构

  1. 代码优化:在迭代开发过程中,需要不断优化代码性能。例如,对于数据库查询,可以使用索引来提高查询速度。在Spring Data JPA中,如果查询方法频繁使用某个字段作为条件,可以在实体类对应的字段上添加@Index注解。另外,对于集合操作,可以选择合适的集合类型,如ArrayList适合随机访问,LinkedList适合频繁插入和删除。

  2. 重构:随着业务的发展,代码可能变得复杂和难以维护,这时需要进行重构。例如,将重复的代码提取到公共方法中,对过长的方法进行拆分,遵循单一职责原则等。比如,在一个控制器类中有多个方法都需要进行用户权限验证,就可以将权限验证代码提取到一个单独的方法中,然后在各个方法中调用。

实战案例:在线商城开发

项目需求分析

  1. 用户模块:包括用户注册、登录、个人信息管理等功能。用户注册时需要验证邮箱和手机号的唯一性,登录时需要进行密码验证。
  2. 商品模块:商品的添加、查询、修改和删除功能。商品需要有分类、价格、库存等属性。
  3. 订单模块:用户可以下单购买商品,订单需要关联用户和商品信息,同时要处理库存扣减和订单状态跟踪等功能。

技术选型

  1. 后端:使用Spring Boot作为框架,Spring Data JPA进行数据访问,MySQL作为数据库,Spring Security进行安全管理。
  2. 前端:可以选择Vue.js或React.js等前端框架,通过RESTful API与后端进行交互。

项目开发过程

  1. 数据库设计:设计用户表、商品表、订单表等。例如,用户表结构如下:
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(50) NOT NULL UNIQUE,
    phone VARCHAR(20) NOT NULL UNIQUE
);

商品表结构如下:

CREATE TABLE products (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock INT NOT NULL,
    category VARCHAR(50)
);

订单表结构如下:

CREATE TABLE orders (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    quantity INT NOT NULL,
    order_status VARCHAR(20) DEFAULT 'PENDING',
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);
  1. 后端开发:创建Spring Boot项目,添加相关依赖。创建实体类、Repository接口、Service层和Controller层。例如,用户实体类User.java
package com.example.onlineshop.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;
    private String phone;

    // getters and setters
}

用户Repository接口UserRepository.java

package com.example.onlineshop.repository;

import com.example.onlineshop.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByEmail(String email);
    User findByPhone(String phone);
}

用户Service层UserService.java

package com.example.onlineshop.service;

import com.example.onlineshop.entity.User;
import com.example.onlineshop.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User registerUser(User user) {
        if (userRepository.findByEmail(user.getEmail()) != null || userRepository.findByPhone(user.getPhone()) != null) {
            throw new IllegalArgumentException("Email or phone already exists");
        }
        return userRepository.save(user);
    }

    public User loginUser(String email, String password) {
        User user = userRepository.findByEmail(email);
        if (user != null && user.getPassword().equals(password)) {
            return user;
        }
        throw new IllegalArgumentException("Invalid email or password");
    }
}

用户Controller层UserController.java

package com.example.onlineshop.controller;

import com.example.onlineshop.entity.User;
import com.example.onlineshop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/register")
    public User register(@RequestBody User user) {
        return userService.registerUser(user);
    }

    @PostMapping("/login")
    public User login(@RequestBody User user) {
        return userService.loginUser(user.getEmail(), user.getPassword());
    }
}
  1. 前端开发:以Vue.js为例,创建Vue项目,使用axios库与后端API进行交互。例如,在components/Register.vue中:
<template>
  <div>
    <form @submit.prevent="register">
      <label>Username:</label>
      <input type="text" v-model="user.username">
      <label>Email:</label>
      <input type="email" v-model="user.email">
      <label>Phone:</label>
      <input type="text" v-model="user.phone">
      <label>Password:</label>
      <input type="password" v-model="user.password">
      <button type="submit">Register</button>
    </form>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: {
        username: '',
        email: '',
        phone: '',
        password: ''
      }
    };
  },
  methods: {
    async register() {
      try {
        const response = await axios.post('/register', this.user);
        console.log(response.data);
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>

通过以上步骤,一个简单的在线商城后端服务就初步搭建完成了,在后续的迭代开发中,可以不断完善功能,优化性能,增加新的业务需求。