mybatis

1.xml方式实现增删改查

添加数据(INSERT):
		
java

		
// 创建一个对象
User user = new User();
user.setName("John");
user.setAge(25);

// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行插入操作
sqlSession.insert("UserMapper.insertUser", user);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在 XML 文件中,定义名为 "UserMapper" 的命名空间,并在其中定义名为 "insertUser" 的 INSERT 语句,如下所示:

		
xml

		
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <insert id="insertUser" parameterType="com.example.model.User">
        INSERT INTO user (name, age)
        VALUES (#{name}, #{age})
    </insert>
</mapper>

    
	
查询数据(SELECT):
		
java

		
// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询操作
List<User> userList = sqlSession.selectList("UserMapper.getUserList");

// 遍历结果
for (User user : userList) {
    System.out.println(user.getName() + ", " + user.getAge());
}

// 关闭 SqlSession
sqlSession.close();

    
	
在 XML 文件中,定义名为 "UserMapper" 的命名空间,并在其中定义名为 "getUserList" 的 SELECT 语句,如下所示:

		
xml

		
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <select id="getUserList" resultType="com.example.model.User">
        SELECT * FROM user
    </select>
</mapper>

    
	
更新数据(UPDATE):
		
java

		
// 创建一个对象
User user = new User();
user.setId(1);
user.setAge(30);

// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行更新操作
sqlSession.update("UserMapper.updateUser", user);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在 XML 文件中,定义名为 "UserMapper" 的命名空间,并在其中定义名为 "updateUser" 的 UPDATE 语句,如下所示:

		
xml

		
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <update id="updateUser" parameterType="com.example.model.User">
        UPDATE user
        SET age = #{age}
        WHERE id = #{id}
    </update>
</mapper>

    
	
删除数据(DELETE):
		
java

		
// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行删除操作
sqlSession.delete("UserMapper.deleteUser", 1);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在 XML 文件中,定义名为 "UserMapper" 的命名空间,并在其中定义名为 "deleteUser" 的 DELETE 语句,如下所示:

		
xml

		
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <delete id="deleteUser" parameterType="int">
        DELETE FROM user
        WHERE id = #{id}
    </delete>
</mapper>

2.mybatis注解实现增删改查

添加数据(INSERT):
		
java

		
// 创建一个对象
User user = new User();
user.setName("John");
user.setAge(25);

// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行插入操作
sqlSession.getMapper(UserMapper.class).insertUser(user);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在对应的 Mapper 接口中,使用 @Insert 注解定义插入方法,如下所示:

		
java

		
// UserMapper.java
public interface UserMapper {
    @Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")
    void insertUser(User user);
}

    
	
查询数据(SELECT):
		
java

		
// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询操作
List<User> userList = sqlSession.getMapper(UserMapper.class).getUserList();

// 遍历结果
for (User user : userList) {
    System.out.println(user.getName() + ", " + user.getAge());
}

// 关闭 SqlSession
sqlSession.close();

    
	
在对应的 Mapper 接口中,使用 @Select 注解定义查询方法,如下所示:

		
java

		
// UserMapper.java
public interface UserMapper {
    @Select("SELECT * FROM user")
    List<User> getUserList();
}

    
	
更新数据(UPDATE):
		
java

		
// 创建一个对象
User user = new User();
user.setId(1);
user.setAge(30);

// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行更新操作
sqlSession.getMapper(UserMapper.class).updateUser(user);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在对应的 Mapper 接口中,使用 @Update 注解定义更新方法,如下所示:

		
java

		
// UserMapper.java
public interface UserMapper {
    @Update("UPDATE user SET age = #{age} WHERE id = #{id}")
    void updateUser(User user);
}

    
	
删除数据(DELETE):
		
java

		
// 调用 MyBatis 的 SQLSessionFactory 获取一个 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行删除操作
sqlSession.getMapper(UserMapper.class).deleteUser(1);

// 提交事务
sqlSession.commit();

// 关闭 SqlSession
sqlSession.close();

    
	
在对应的 Mapper 接口中,使用 @Delete 注解定义删除方法,如下所示:

		
java

		
// UserMapper.java
public interface UserMapper {
    @Delete("DELETE FROM user WHERE id = #{id}")
    void deleteUser(int id);
}

    
	
以上示例中,假设存在一个 User 类,具有 id、name 和 age 属性,对应数据库中的 user 表。在对应的 Mapper 接口中,使用相应的注解来定义数据库操作方法,并通过 MyBatis 的 SqlSession 对象执行这些操作。需要根据实际情况进行替换和调整,包括数据库表名、列名、实体类名以及注解中的 SQL 语句等。

3.mybatis的动态sql

MyBatis 提供了动态 SQL 的功能,可以根据不同的条件生成不同的 SQL 语句,以满足不同的查询需求。以下是几种常见的 MyBatis 动态 SQL 的用法:

if 条件判断:
		
xml

		
<select id="getUserList" resultType="com.example.model.User">
  SELECT * FROM user
  WHERE 1=1
  <if test="name != null">
    AND name = #{name}
  </if>
  <if test="age != null">
    AND age = #{age}
  </if>
</select>

    
	
在上述示例中,根据传入的参数 name 和 age 进行条件判断,如果参数不为空,则在 SQL 语句中添加相应的条件。

choose、when、otherwise 条件选择:
		
xml

		
<select id="getUserList" resultType="com.example.model.User">
  SELECT * FROM user
  WHERE 1=1
  <choose>
    <when test="name != null">
      AND name = #{name}
    </when>
    <when test="age != null">
      AND age = #{age}
    </when>
    <otherwise>
      AND status = 'active'
    </otherwise>
  </choose>
</select>

    
	
在上述示例中,根据传入的参数 name 和 age 进行条件选择,如果 name 不为空,则添加 name 的条件;如果 age 不为空,则添加 age 的条件;否则,默认添加 status = 'active' 的条件。

foreach 循环遍历:
		
xml

		
<select id="getUserList" resultType="com.example.model.User">
  SELECT * FROM user
  WHERE id IN
  <foreach collection="ids" item="id" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

    
	
在上述示例中,根据传入的参数 ids 进行循环遍历,将 ids 中的元素拼接成 IN 条件的形式。

trim、set、where 动态片段:
		
xml

		
<update id="updateUser" parameterType="com.example.model.User">
  UPDATE user
  <set>
    <if test="name != null">
      name = #{name},
    </if>
    <if test="age != null">
      age = #{age},
    </if>
  </set>
  WHERE id = #{id}
</update>

    
	
在上述示例中,根据传入的参数进行条件判断,并动态生成 SET 子句。如果 name 不为空,则添加 name 的更新;如果 age 不为空,则添加 age 的更新。最后,根据 id 进行条件匹配。

4.文件上传

以下是使用 Java 实现文件上传的示例代码:

		
java

		
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet("/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取上传的文件
        Part filePart = request.getPart("file");
        String fileName = filePart.getSubmittedFileName();
        
        // 保存文件到指定路径
        String uploadDir = "C:/uploads"; // 上传文件保存的目录
        Path filePath = Files.createTempFile(uploadDir, fileName);
        
        try (InputStream inputStream = filePart.getInputStream();
                OutputStream outputStream = new FileOutputStream(filePath.toFile())) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
        
        response.getWriter().println("文件上传成功!");
    }
}

    
	
上述代码实现了一个简单的文件上传功能。在 doPost 方法中,首先通过 request.getPart("file") 获取上传的文件,然后获取文件名,并确定保存文件的目录。接下来,使用 Files.createTempFile 方法创建一个临时文件,并将上传的文件内容写入到该文件中。最后,通过 response.getWriter().println 输出上传成功的信息。

需要注意的是,为了能够支持文件上传,需要在 Servlet 类上添加 @MultipartConfig 注解,并在 web.xml 文件中配置 multipart-config。

在前端页面中,可以使用 <input type="file" name="file"> 的形式添加一个文件选择框,并将其包含在一个表单中,然后将表单的 enctype 属性设置为 multipart/form-data。

5.文件下载

以下是使用 Java 实现文件下载的示例代码:

		
java

		
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取要下载的文件路径
        String filePath = "C:/uploads/example.pdf"; // 要下载的文件路径
        
        // 设置响应头信息
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + getFileName(filePath) + "\"");

        // 读取文件并写入响应输出流
        try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(filePath));
                OutputStream outputStream = response.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }

    private String getFileName(String filePath) {
        File file = new File(filePath);
        return file.getName();
    }
}

    
	
上述代码实现了一个简单的文件下载功能。在 doGet 方法中,首先获取要下载的文件路径,然后设置响应头信息,包括设置响应的内容类型为 application/octet-stream,并设置 Content-Disposition 头部,指定下载文件的文件名。接下来,使用 BufferedInputStream 读取文件内容,并通过 response.getOutputStream() 获取响应输出流,将文件内容写入到响应输出流中。

在前端页面中,可以使用一个链接或按钮,将请求发送到 /download 路径,然后服务器会返回要下载的文件。

需要注意的是,以上示例中的文件路径是硬编码的,实际应用中需要根据实际情况进行替换。

此外,还可以在代码中添加错误处理,例如当文件不存在或无法读取时,可以返回一个错误页面或给出相应的提示信息。

6.登录

以下是使用 Spring Boot 实现用户登录业务的示例代码:

创建一个用户实体类 User.java,包含用户名和密码字段:
		
java

		
public class User {
    private String username;
    private String password;

    // 省略构造方法、getter 和 setter 方法
}

    
	
创建一个用户服务类 UserService.java,用于处理用户登录逻辑:
		
java

		
import org.springframework.stereotype.Service;

@Service
public class UserService {

    public boolean login(String username, String password) {
        // 假设这里是从数据库或其他数据源中获取用户信息进行验证
        // 这里只是简单模拟,实际应用中需要根据实际情况进行替换
        if ("john".equals(username) && "password123".equals(password)) {
            return true;
        } else {
            return false;
        }
    }
}

    
	
创建一个控制器类 LoginController.java,用于处理登录请求:
		
java

		
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 LoginController {

    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public String login(@RequestBody User user) {
        if (userService.login(user.getUsername(), user.getPassword())) {
            return "登录成功";
        } else {
            return "用户名或密码错误";
        }
    }
}

    
	
创建一个 Spring Boot 应用主类 Application.java,用于启动应用:
		
java

		
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

    
	
在上述示例中,通过 UserService 类处理用户登录逻辑,LoginController 类处理登录请求,并将验证结果返回给客户端。在 Application 类中启动 Spring Boot 应用。

需要在 application.properties 或 application.yml 配置文件中配置数据库连接等相关信息,以便从数据库中获取用户信息进行验证。

7.JWT的实现

以下是使用 Spring Boot 实现 JWT(JSON Web Token)认证和授权的示例代码:

添加依赖: 在 pom.xml 文件中添加以下依赖:
		
xml

		
<dependencies>
    <!-- Spring Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

    
	
创建一个 JWT 工具类 JwtUtil.java,用于生成和解析 JWT:
		
java

		
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtUtil {

    private static final String SECRET_KEY = "your-secret-key";
    private static final long EXPIRATION_TIME = 86400000; // 24 hours

    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();

        return claims.getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }
}

    
	
创建一个自定义的用户认证类 JwtUserDetailsService.java,用于验证用户身份:
		
java

		
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class JwtUserDetailsService implements UserDetailsService {

    private static final Map<String, String> users = new HashMap<>();

    public JwtUserDetailsService() {
        // 模拟用户数据,实际应用中可以从数据库或其他数据源中获取
        users.put("john", "password123");
        users.put("mary", "password456");
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (users.containsKey(username)) {
            String password = users.get(username);
            return new User(username, password, new ArrayList<>());
        } else {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
    }
}

    
	
创建一个控制器类 LoginController.java,用于处理登录请求和生成 JWT:
		
java

		
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody AuthenticationRequest authenticationRequest) {
        try {
            // 进行身份验证
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
            );
        } catch (AuthenticationException e) {
            // 身份验证失败
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
        }

        // 生成 JWT
        UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
        String token = jwtUtil.generateToken(userDetails.getUsername());

        // 返回 JWT
        return ResponseEntity.ok(new AuthenticationResponse(token));
    }
}

    
	
创建一个身份验证请求类 AuthenticationRequest.java,用于接收登录请求的用户名和密码:
		
java

		
public class AuthenticationRequest {

    private String username;
    private String password;

    // 省略构造方法、getter 和 setter 方法
}

    
	
创建一个身份验证响应类 AuthenticationResponse.java,用于返回登录成功

8.过滤器

在 Spring Boot 中,可以使用过滤器(Filter)来对请求进行预处理和后处理。下面是一个简单的示例,展示如何在 Spring Boot 中实现过滤器业务:

创建一个实现了 javax.servlet.Filter 接口的过滤器类:
		
java

		
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 在请求处理之前进行预处理
        System.out.println("Before Filter");

        // 调用下一个过滤器(如果有的话)或者目标资源
        filterChain.doFilter(request, response);

        // 在请求处理之后进行后处理
        System.out.println("After Filter");
    }
}

    
	
在 Spring Boot 应用中注册过滤器:
		
java

		
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyFilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistrationBean() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/*"); // 指定过滤器的 URL 匹配模式
        registrationBean.setOrder(1); // 设置过滤器的优先级
        return registrationBean;
    }
}

    
	
在上述示例中,创建了一个名为 MyFilter 的过滤器类,并实现了 doFilter 方法,在该方法中可以进行请求的预处理和后处理。然后,在 MyFilterConfig 配置类中,通过 FilterRegistrationBean 注册了该过滤器,并指定了过滤器的 URL 匹配模式和优先级。

9.拦截器

在 Spring Boot 中,可以使用拦截器(Interceptor)对请求进行预处理和后处理。下面是一个简单的示例,展示如何在 Spring Boot 中实现拦截器业务:

创建一个实现了 HandlerInterceptor 接口的拦截器类:
		
java

		
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理之前进行预处理
        System.out.println("Before Interceptor");
        return true; // 返回 true 表示继续执行后续的拦截器和处理器方法,返回 false 表示终止请求处理
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求处理之后进行后处理
        System.out.println("After Interceptor");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在请求完成之后进行清理工作
        System.out.println("After Completion");
    }
}

    
	
在 Spring Boot 应用中注册拦截器:
		
java

		
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**") // 指定拦截器的 URL 匹配模式
                .excludePathPatterns("/public/**"); // 指定不需要拦截的 URL
    }
}

    
	
在上述示例中,创建了一个名为 MyInterceptor 的拦截器类,并实现了 preHandle、postHandle 和 afterCompletion 方法,在这些方法中可以进行请求的预处理、后处理和清理工作。然后,在 MyInterceptorConfig 配置类中,通过 addInterceptors 方法注册了该拦截器,并指定了拦截器的 URL 匹配模式和不需要拦截的 URL。

10.异常处理

在 Spring Boot 中,可以通过统一结果返回类来统一处理接口的响应结果,包括成功和失败的情况。以下是一个示例代码:

创建一个统一结果返回类 ApiResponse.java:
		
java

		
public class ApiResponse {
    private int code;
    private String message;
    private Object data;

    public ApiResponse(int code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    // 省略 getter 和 setter 方法
}

    
	
创建一个工具类 ApiResultUtil.java 用于生成不同场景下的统一结果返回:
		
java

		
public class ApiResultUtil {

    public static ApiResponse success(Object data) {
        return new ApiResponse(200, "Success", data);
    }

    public static ApiResponse error(int code, String message) {
        return new ApiResponse(code, message, null);
    }
}

    
	
在控制器中使用统一结果返回类:
		
java

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

@RestController
public class MyController {

    @GetMapping("/api/data")
    public ApiResponse getData() {
        // 模拟成功的情况
        Object data = getDataFromService();
        return ApiResultUtil.success(data);
    }

    @GetMapping("/api/error")
    public ApiResponse getError() {
        // 模拟失败的情况
        return ApiResultUtil.error(500, "Error occurred");
    }

    private Object getDataFromService() {
        // 从服务层获取数据
        return "Some data";
    }
}

    
	
在上述示例中,创建了一个 ApiResponse 类用于封装统一的结果返回,包括响应码、消息和数据。通过 ApiResultUtil 工具类提供了 success 和 error 方法来生成成功和失败的结果返回。在控制器中,根据业务逻辑调用相应的方法并使用统一结果返回类返回结果。

11.spring的事务

在 Spring 中,事务是一种管理数据库操作的机制,用于确保一组操作要么全部成功提交,要么全部失败回滚。Spring 提供了对事务的支持,可以通过声明式事务管理或编程式事务管理来管理事务。

声明式事务管理: 通过使用注解或 XML 配置来声明事务的边界和属性。
使用注解方式: 在 Spring Boot 应用中,可以使用 @Transactional 注解来声明事务的边界和属性。将该注解应用在方法或类上,以指示该方法或类需要进行事务管理。
		
java

		
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
    }
}

    
	
使用 XML 配置方式: 在 Spring 的 XML 配置文件中,通过 <tx:advice> 和 <tx:annotation-driven> 元素来声明事务管理器和开启注解事务支持。
		
xml

		
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="create*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="userServicePointcut" expression="execution(* com.example.UserService.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointcut" />
</aop:config>

    
	
编程式事务管理: 通过在代码中显式地使用事务管理器来控制事务的边界和属性。
		
java

		
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void createUser(User user) {
        TransactionDefinition definition = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            userRepository.save(user);
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

    
	
在编程式事务管理中,需要注入一个 PlatformTransactionManager 实例,并使用该实例来获取事务定义和事务状态,并在需要的地方手动提交或回滚事务。

spring传播行为

 

Spring 的事务传播行为是用来定义在多个事务方法相互调用时,事务应该如何传播和管理的规则。Spring 提供了多种事务传播行为,可以根据需求选择适合的传播行为。

以下是 Spring 支持的事务传播行为及其说明:

REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。这是最常用的传播行为。

REQUIRES_NEW:无论当前是否存在事务,都会创建一个新的事务。如果当前存在事务,则将当前事务挂起。

NESTED:如果当前存在事务,则在该事务的嵌套事务中执行;如果当前没有事务,则创建一个新事务。嵌套事务是独立的,有自己的保存点,可以选择回滚或提交。

SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。

NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将当前事务挂起。

MANDATORY:要求当前必须存在事务,否则抛出异常。

NEVER:要求当前必须不存在事务,否则抛出异常。

下面是一个示例代码,展示如何在 Spring Boot 中实现不同的事务传播行为:

		
java

		
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void createUser(User user) {
        userRepository.save(user);
        updateUserStatistics();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateUserStatistics() {
        // 更新用户统计信息
    }
}

    
	
在上述示例中,createUser 方法使用了 Propagation.REQUIRED 的事务传播行为,表示如果当前存在事务,则在当前事务中执行;如果当前没有事务,则创建一个新事务。而 updateUserStatistics 方法使用了 Propagation.REQUIRES_NEW 的事务传播行为,表示无论当前是否存在事务,都会创建一个新的事务。

通过在 @Transactional 注解中指定 propagation 属性,可以设置不同的事务传播行为。可以根据具体的业务需求选择合适的传播行为,确保事务的一致性和正确性。

12.AOP

在 Spring 中,AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,通过将横切关注点(如日志记录、事务管理、安全性检查等)从业务逻辑中分离出来,以模块化的方式进行处理。Spring 提供了对 AOP 的支持,可以通过切面(Aspect)来定义横切关注点,并将其应用到目标对象的方法上。

以下是 Spring AOP 的主要概念和用法:

切面(Aspect):定义了横切关注点的类。切面通常包含切点和通知。

切点(Pointcut):定义了哪些方法将被拦截和应用切面逻辑的位置。Spring 提供了多种切点表达式,如基于方法名、注解、包路径等。

通知(Advice):定义了在切点被拦截时执行的逻辑。常见的通知类型包括前置通知(Before)、后置通知(After)、返回通知(AfterReturning)和异常通知(AfterThrowing)。

连接点(Join Point):在程序执行过程中可以被拦截的特定点。连接点可以是方法调用、方法执行、字段访问等。

织入(Weaving):将切面逻辑应用到目标对象的过程。织入可以在编译时、类加载时或运行时进行。

在 Spring 中,可以通过注解和 XML 配置的方式来定义切面和通知。

使用注解方式:

		
java

		
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        // 前置通知逻辑
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        // 返回通知逻辑
        System.out.println("After returning method: " + joinPoint.getSignature().getName() + ", result: " + result);
    }

    // 其他通知类型的定义...
}

    
	
使用 XML 配置方式:

		
xml

		
<bean id="loggingAspect" class="com.example.LoggingAspect" />

<aop:config>
    <aop:aspect ref="loggingAspect">
        <aop:before pointcut="execution(* com.example.service.*.*(..))" method="beforeAdvice" />
        <aop:after-returning pointcut="execution(* com.example.service.*.*(..))" method="afterReturningAdvice" returning="result" />
        <!-- 其他通知类型的配置... -->
    </aop:aspect>
</aop:config>

    
	
在上述示例中,LoggingAspect 类定义了切面和通知的逻辑。通过 @Aspect 注解标记该类为切面,并使用注解方式或 XML 配置方式定义切点和通知。例如,@Before 注解定义了前置通知的逻辑,@AfterReturning 注解定义了返回通知的逻辑。

 spring的AOP实现

在业务中,Spring AOP 可以用于实现各种横切关注点的逻辑,如日志记录、缓存、权限控制等。下面以日志记录为例,展示如何在业务中使用 Spring AOP:

创建一个切面类 LoggingAspect.java,用于定义日志记录的逻辑:
		
java

		
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Before method: " + methodName);
        // 记录日志逻辑...
    }

    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("After returning method: " + methodName + ", result: " + result);
        // 记录日志逻辑...
    }
}

    
	
在业务服务类中,添加需要进行日志记录的方法:
		
java

		
@Service
public class UserService {

    public void createUser(User user) {
        // 业务逻辑...
    }

    public User getUserById(int id) {
        // 业务逻辑...
        return user;
    }
}

    
	
通过在切面类 LoggingAspect.java 中定义的切点和通知,可以拦截并记录 UserService 类中的方法调用日志。例如,beforeAdvice 方法在目标方法调用前执行,记录方法名;afterReturningAdvice 方法在目标方法成功返回后执行,记录方法名和返回结果。

配置 Spring AOP,使切面生效:
		
xml

		
<aop:aspectj-autoproxy />
<context:component-scan base-package="com.example" />

    
	
在 Spring 的 XML 配置文件中,配置 <aop:aspectj-autoproxy /> 启用 Spring AOP 的自动代理功能,使切面生效。通过 <context:component-scan> 配置扫描需要拦截的业务类所在的包。

13.spring的bean

在 Spring 中,Bean 是由 Spring 容器管理的对象。Bean 是应用的核心组件,由 Spring 容器负责创建、配置和管理。通过 Spring 的依赖注入机制,可以在应用中方便地使用和管理 Bean。

以下是关于 Spring 的 Bean 的一些重要概念和用法:

Bean 的定义:
在 Spring 中,Bean 可以通过 XML 配置文件或注解方式进行定义。在 XML 配置文件中,通过 <bean> 元素来定义 Bean,指定 Bean 的类名、属性、依赖等。在注解方式中,通过 @Component、@Service、@Repository、@Controller 等注解来定义 Bean。

Bean 的作用域:
Spring 提供了多种 Bean 的作用域,包括 singleton(单例)、prototype(原型)、request(请求)、session(会话)等。默认情况下,Bean 的作用域是 singleton,即每个 Spring 容器中只有一个实例。

Bean 的生命周期:
Spring 容器管理 Bean 的生命周期,包括实例化、属性设置、初始化、销毁等阶段。可以通过实现 InitializingBean 和 DisposableBean 接口或使用 @PostConstruct 和 @PreDestroy 注解来定义 Bean 的初始化和销毁方法。

Bean 的依赖注入:
Spring 支持通过构造函数注入、属性注入、方法注入等方式来注入 Bean 之间的依赖关系。可以通过 XML 配置文件或注解方式来指定 Bean 之间的依赖关系。

Bean 的自动装配:
Spring 提供了自动装配的功能,可以根据类型、名称、注解等自动将 Bean 注入到目标 Bean 中。可以通过 @Autowired、@Resource、@Inject 注解来实现自动装配。

Bean 的加载和获取:
Spring 容器可以通过 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext 等方式加载 Bean 的配置文件或注解配置,然后通过容器获取 Bean 实例。

下面是一个简单的示例,展示如何定义和使用 Bean:

定义一个简单的 UserService Bean:

		
java

		
@Component
public class UserService {
    public void createUser(String username) {
        System.out.println("User created: " + username);
    }
}

    
	
在应用中使用 UserService Bean:

		
java

		
@Service
public class UserServiceImpl {

    @Autowired
    private UserService userService;

    public void registerUser(String username) {
        userService.createUser(username);
    }
}

    
	
在上述示例中,UserService 类被定义为一个 Bean,并通过 @Component 注解标记为 Spring 管理的组件。UserServiceImpl 类中使用了 @Autowired 注解将 UserService Bean 注入到该类中,然后调用 UserService Bean 的方法。

14.spring的IOC

IOC(Inversion of Control,控制反转)是 Spring 框架的核心概念之一,也是 Spring 容器的基本原理。IOC 实现了对象的创建、依赖关系的管理和对象的生命周期的控制,通过将对象的控制权交给容器来实现解耦和灵活性。

以下是关于 Spring 的 IOC 的一些重要概念和用法:

Bean:在 Spring 中,Bean 是由 Spring 容器管理的对象。Bean 可以通过 XML 配置文件或注解方式进行定义,并由 Spring 容器负责创建、配置和管理。

容器:Spring 容器是 IOC 的核心,负责管理 Bean 的生命周期和依赖关系。Spring 提供了多种容器实现,如 ApplicationContext、BeanFactory 等。

依赖注入:通过依赖注入,容器将 Bean 之间的依赖关系注入到对象中。依赖注入可以通过构造函数注入、属性注入、方法注入等方式来实现。

配置元数据:配置元数据是描述 Bean 的信息和依赖关系的数据,可以通过 XML 配置文件或注解方式来定义。XML 配置文件中使用 <bean> 元素来定义 Bean,注解方式使用 @Component、@Service、@Repository、@Controller 等注解来定义 Bean。

生命周期管理:Spring 容器管理 Bean 的生命周期,包括实例化、属性设置、初始化、销毁等阶段。可以通过实现 InitializingBean 和 DisposableBean 接口或使用 @PostConstruct 和 @PreDestroy 注解来定义 Bean 的初始化和销毁方法。

自动装配:Spring 提供了自动装配的功能,可以根据类型、名称、注解等自动将 Bean 注入到目标 Bean 中。可以通过 @Autowired、@Resource、@Inject 注解来实现自动装配。

AOP:AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的另一个重要特性,通过 AOP 可以将横切关注点的逻辑从业务逻辑中分离出来,实现模块化的处理。

通过 IOC,Spring 实现了对象的解耦和可配置性,提高了代码的可维护性和可测试性。通过依赖注入和自动装配,可以方便地管理对象之间的依赖关系。通过生命周期管理和 AOP,可以实现对对象的统一管理和横切关注点的处理。

 spring的IOC在具体业务实现

在 Spring Boot 中实现 IOC 的方式与传统的 Spring 应用程序类似,可以通过注解方式声明 Bean、依赖注入和配置管理。下面是在 Spring Boot 中实现 IOC 的一些常见方式:

创建和管理 Bean:

在 Spring Boot 应用程序中,可以使用 @Component、@Service、@Repository、@Controller 等注解将类声明为 Spring 管理的 Bean。
Spring Boot 会自动扫描并注册带有这些注解的类,无需额外的配置。
依赖注入:

在 Spring Boot 应用程序中,可以使用 @Autowired 注解将依赖的 Bean 注入到属性、构造函数或方法中。
Spring Boot 会自动进行依赖注入,无需手动配置依赖关系。
配置管理:

在 Spring Boot 应用程序中,可以使用 @Value 注解将属性值从配置文件中注入到 Bean 中。
Spring Boot 支持在 application.properties 或 application.yml 配置文件中定义属性值,这些值可以通过 @Value 注解注入到 Bean 中。
生命周期管理:

在 Spring Boot 应用程序中,可以使用 @PostConstruct 和 @PreDestroy 注解标记初始化和销毁方法。
Spring Boot 会自动调用标记了这些注解的方法,无需手动管理 Bean 的生命周期。
AOP 横切关注点处理:

在 Spring Boot 应用程序中,可以使用 @Aspect 注解定义切面类,通过 @Before、@After、@Around 等注解定义通知方法,实现横切关注点的逻辑。
Spring Boot 默认集成了 Spring AOP,可以直接在应用中使用 AOP 功能。
通过 Spring Boot 的自动配置和集成,开发者可以更加便捷地实现 IOC 和 AOP 功能,提高开发效率。Spring Boot 的简化配置和快速启动特性使得开发者可以专注于业务逻辑的实现,而不用过多关注底层的配置和细节。因此,Spring Boot 是一种非常适合开发微服务和快速原型开发的框架。

15.springboot

Spring Boot 是一个用于创建独立、可执行的 Spring 应用程序的框架。它简化了 Spring 应用程序的开发过程,提供了自动配置、快速启动、约定优于配置等特性,使得开发者可以更加轻松地搭建和部署应用程序。

Spring Boot 的一些核心特点和功能包括:

自动配置:Spring Boot 根据应用程序的依赖关系自动配置 Spring 框架的各种组件和功能。它通过类路径上的依赖和约定来自动配置,并提供了一套默认的配置,减少了手动配置的工作量。

快速启动:Spring Boot 提供了一个嵌入式的服务器(如 Tomcat、Jetty),可以直接运行 Spring Boot 应用程序,无需部署到外部服务器。这样可以快速启动和测试应用程序,提高开发效率。

简化配置:Spring Boot 采用了约定优于配置的原则,通过默认配置和约定来减少配置的复杂性。开发者只需要关注核心业务逻辑,而不必过多关注底层的配置细节。

微服务支持:Spring Boot 提供了对构建微服务架构的支持,包括对 RESTful 接口的开发、服务注册与发现、负载均衡、熔断器等功能的集成。

监控和管理:Spring Boot 提供了一套健康检查、指标监控、日志管理等功能,方便开发者对应用程序进行监控和管理。

外部化配置:Spring Boot 支持将应用程序的配置外部化,可以使用属性文件、环境变量、命令行参数等方式来配置应用程序的行为。

嵌入式数据库支持:Spring Boot 支持嵌入式数据库(如 H2、HSQLDB),可以方便地在开发环境中使用,无需额外的数据库安装和配置。

总之,Spring Boot 是一个简化了 Spring 应用程序开发的框架,它提供了强大的功能和便捷的开发体验。借助 Spring Boot,开发者可以更加专注于业务逻辑的实现,而不用过多关注底层的配置和细节。同时,Spring Boot 也提供了丰富的扩展和集成能力,可以与各种技术和框架无缝集成,满足不同场景和需求的开发。

 springboot的自动装配原理

Spring Boot 的自动装配(Auto-Configuration)是其核心特性之一,它通过分析应用程序的类路径和依赖关系来自动配置 Spring 框架的各种组件和功能。自动装配的原理主要包括以下几个方面:

条件化装配:Spring Boot 使用条件注解(@Conditional)来判断是否满足某些条件,从而决定是否进行自动装配。条件注解可以基于属性、类路径、环境变量等多个条件进行判断。

Spring Boot Starter:Spring Boot Starter 是一种特殊的依赖,它集成了一组相关的依赖和配置,用于快速启动某个功能或技术栈。Spring Boot Starter 通过自动配置类(@Configuration)和条件注解来实现自动装配。

自动配置类:Spring Boot 使用自动配置类来定义和配置各种组件和功能。自动配置类使用 @Configuration 注解进行标记,并通过 @EnableAutoConfiguration 注解启用自动配置。自动配置类中通常会使用 @Conditional 注解来设置条件,只有满足条件时才会进行自动装配。

Spring Factories Loader:Spring Boot 使用 META-INF/spring.factories 文件来加载自动配置类。该文件中定义了各个自动配置类的全限定类名,Spring Boot 在启动时会加载这些配置类,并根据条件进行自动装配。

自定义自动配置:开发者可以通过编写自定义的自动配置类来扩展和定制 Spring Boot 的自动装配。自定义自动配置类需要遵循一定的命名规则,并且要将其添加到 META-INF/spring.factories 文件中。

16.springboot自定义starter

自定义 Spring Boot Starter 是一种将常用功能、依赖和配置打包成一个可重用的模块,供其他 Spring Boot 应用程序使用的方式。通过自定义 Starter,可以将一组相关的功能打包成一个独立的模块,使得应用程序的配置和依赖管理更加简洁和方便。

下面是自定义 Spring Boot Starter 的基本步骤:

创建一个 Maven 或 Gradle 项目,并在项目中添加所需的功能、依赖和配置。这些功能可以是一组自定义的 Bean、配置类、工具类等。

创建一个自动配置类(AutoConfiguration),用于定义自定义功能的配置和装配逻辑。自动配置类需要使用 @Configuration 注解进行标记,并在类上使用 @EnableAutoConfiguration 注解启用自动配置。

在 META-INF/spring.factories 文件中添加自动配置类的全限定类名,以便 Spring Boot 能够加载自定义的自动配置类。

创建一个 Starter 模块,该模块是一个普通的 Maven 或 Gradle 项目,并在项目中引入自定义功能和自动配置类。可以在 Starter 模块中定义一些默认的配置或属性,以便在其他应用程序中使用时进行自定义配置。

在 Starter 模块的 src/main/resources 目录下创建 META-INF/spring.factories 文件,并添加自定义 Starter 的配置类的全限定类名,以便其他应用程序能够引入 Starter。

将自定义的 Starter 模块发布到 Maven 中央仓库或私有仓库,以便其他应用程序可以引入并使用。

在其他 Spring Boot 应用程序中,通过 Maven 或 Gradle 的依赖管理工具引入自定义 Starter 模块,并在应用程序的配置文件中进行必要的配置。
创建一个 Maven 项目,并在 pom.xml 文件中添加必要的依赖。

创建一个自动配置类 CustomStarterAutoConfiguration,并使用 @Configuration 注解进行标记。

		
java

		
@Configuration
public class CustomStarterAutoConfiguration {
   // 在这里定义自定义的配置和装配逻辑
}

    
	
在 src/main/resources 目录下创建 META-INF/spring.factories 文件,并添加自动配置类的全限定类名。
		

		
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.CustomStarterAutoConfiguration

    
	
创建一个 Starter 模块,并在 pom.xml 文件中添加依赖和配置。
		
xml

		
<dependencies>
   <!-- 添加所需的依赖 -->
</dependencies>

    
	
在 Starter 模块的 src/main/resources 目录下创建 META-INF/spring.factories 文件,并添加自定义 Starter 的配置类的全限定类名。
		

		
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.CustomStarterAutoConfiguration

    
	
在 Starter 模块的 src/main/resources 目录下创建 application.properties 文件,并添加一些默认的配置。
		

		
# 添加一些默认的配置

    
	
在 Maven 或 Gradle 构建工具中将 Starter 模块发布到本地或远程仓库。

在其他 Spring Boot 应用程序中,通过 Maven 或 Gradle 的依赖管理工具引入自定义 Starter 模块。

		
xml

		
<dependencies>
   <dependency>
      <groupId>com.example</groupId>
      <artifactId>custom-starter</artifactId>
      <version>1.0.0</version>
   </dependency>
</dependencies>

    
	
在应用程序的配置文件中进行必要的配置。

17.springboot的注解

Spring Boot 提供了许多注解,用于简化和增强 Spring 应用程序的开发。下面列举一些常用的 Spring Boot 注解:

@SpringBootApplication: 用于标记主类,表示这是一个 Spring Boot 应用程序的入口类。它是一个组合注解,包括 @Configuration、@EnableAutoConfiguration 和 @ComponentScan。

@RestController: 用于标记 RESTful 接口的控制器类,表示该类中的方法返回的是 JSON 或 XML 格式的数据。

@RequestMapping: 用于映射 URL 到控制器方法,指定请求的路径和 HTTP 方法。

@PathVariable: 用于获取 URL 中的路径参数的值。

@RequestParam: 用于获取请求参数的值。

@RequestBody: 用于获取请求体中的数据,常用于处理 POST 请求的 JSON 数据。

@ResponseBody: 用于将方法的返回值直接作为响应体返回给客户端,常用于处理 RESTful 接口。

@Autowired: 用于自动装配依赖,可以用于字段、构造函数和方法上。

@Value: 用于注入配置文件中的属性值。

@ConfigurationProperties: 用于将配置文件中的属性值注入到一个 Java Bean 中。

@EnableAutoConfiguration: 用于启用 Spring Boot 的自动配置功能。

@ComponentScan: 用于扫描指定包下的组件,可自动注册为 Spring 容器的 Bean。

@Conditional: 用于根据条件来决定是否进行装配或配置。

@EnableConfigurationProperties: 用于启用某个配置类的属性绑定功能。

@EnableScheduling: 用于启用定时任务调度功能。

@EnableAsync: 用于启用异步方法调用功能。

@EnableCaching: 用于启用缓存功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值