程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Spring Boot -- 认识Spring Boot

在前面我们已经学习过Srping MVC框架,我们需要配置web.xml、spring mvc配置文件,tomcat,是不是感觉配置较为繁琐。那我们今天不妨来试试使用Spring Boot,Spring Boot让我们的Spring应用变的更轻量化。比如:你可以仅仅依靠一个Java类来运行一个Spring引用。你也可以打包你的应用为jar并通过使用java -jar来运行你的Spring Web应用。

一 Spring Boot简介

1.1、Spring Boot特点

  • 开箱即用,提供各种默认配置来简化项目配置;
  • 内嵌式容器简化Web项目;
  • 没有冗余代码生成和XML配置的要求;

1.2、Spring Boot和Spring MVC区别

Spring Boot 是一个快速开发的框架,能够快速的整合第三方常用框架(Maven继承方式),简化XML配置,全部采用注解形式,Spring Boot项目中没有web.xml,内置Http服务器(Tomcat、Jetty),默认嵌入Tomcat服务器,最终是以Java应用程序运行。Spring Boot的Web组件默认集成的是Spring MVC框架,Spring MVC是控制层。

注意:Spring Boot使用注解方式启动Spring MVC,详情参考博客:Spring MVC -- 基于注解的控制器

1.3、Spring Boot和Spring Cloud区别

Spring Cloud依赖Spring Boot组件,使用Spring Boot编写Http协议接口,Spring Cloud是一套目前完整的微服务框架,功能非常强大。注册中心、客户端调用工具、服务治理(负载均衡、断路器、分布式配置中心、网关、服务链路、消息总线等)。

二、创建第一个Spring Boot项目

环境要求:Java1.8及以上、Spring Framework 4.1.5及以上。

开发工具:IDEA 2019。

2.1、新建项目

点击File->New Project->选择Maven,点击Next,填写如下信息:

2.2、pom文件引入依赖

复制代码
<!--  spring-boot-starter-parent  整合第三方常用框架依赖信息(各种依赖信息)-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>

    <!--  spring-boot-starter-web  整合Spring MVC Web  -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--  为什么不需要版本号,在parent里面已经封装好了版本号 -->
        </dependency>
    </dependencies>
复制代码

spring-boot-starter-parent作用:在pom.xml中引入spring-boot-starter-parent,spring官方的解释叫什么stater poms,它可以提供dependency management,也就是说依赖管理,引入以后再引入其它dependency的时候就不需要version了;
spring-boot-starter-web作用:Spring Web 核心组件,整合了Spring MVC所用到的jar,主要包括spring-aop、spring-beans、spring-context、spring-core、spring-web、spring-webmvc;

这里主要是利用的maven的父子依赖关系实现的。

2.3、简单demo

创建一个包 com.zy.example.member.controller,新增MemberController.java代码:

复制代码
package com.zy.example.member.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Spring Boot2.0第一个案例
 *
 * @author zy
 * @since 2020-2-2
 */
@RestController
@EnableAutoConfiguration
public class MemberController {
    //@RestController注解表示该类中所有方法返回json格式  等价于@Controller+@ReponseBody
    //Spring Boot启动原理:Spring MVC注解方式启动,不需要web.xml文件 默认内置tomcat服务器
    @RequestMapping("/memberIndex")
    public String memberIndex(){
        return "Spring Boot2.0全新版本教程!";
    }

    public static void main(String[] args){
        //整个程序入口 启动Spring Boot项目
        SpringApplication.run(MemberController.class,args);
    }
}
复制代码

在上面代码中,我们使用到了如下注解:

  • @RestController:表示修饰该Controller所有的方法返回JSON格式,直接可以编写Restful接口;

  • @EnableAutoConfiguration注解:作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,这个注解告诉Spring Boot根据pom中添加的jar依赖猜测你想如何配置Spring。由于spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。

启动主程序,打开浏览器访问http://localhost:8080//memberIndex,可以看到页面输出Spring Boot2.0全新版本教程!

注意每个请求处理方法可以有多个不同类型的参数,以及一个多种类型的返回结果,具体可以参考 编写请求处理方法。以memberIndex()函数为例,返回值为String类型、由于使用了@RestController注解,表示返回的是json字符串,如果将注解修改为@Controller,则返回的是代表逻辑视图名的String。

2.4、其它启动方式

小节3中的启动方式,默认只扫描当前包,如果存在多个控制器,是无法扫描到的,我们可以通过@ComponentScan实现,修改MemberController.java文件如下:

复制代码
package com.zy.example.member.controller;

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

/**
 * Spring Boot2.0第一个案例
 *
 * @author zy
 * @since 2020-2-2
 */
@RestController
public class MemberController {
    //@RestController注解表示该类中所有方法返回json格式  等价于@Controller+@ReponseBody
    //Spring Boot启动原理:Spring MVC注解方式启动,不需要web.xml文件 默认内置tomcat服务器
    @RequestMapping("/memberIndex")
    public String memberIndex(){
        return "Spring Boot2.0全新版本教程!";
    }
}
复制代码

创建启动文件App.java:

复制代码
package com.zy.example.member.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * 启动代码
 *
 * @author zy
 * @since 2020-2-2
 */
@ComponentScan("com.zy.example.member.controller")
public class App {
    public static void main(String[] args){
        //整个程序入口 启动Spring Boot项目
        SpringApplication.run(MemberController.class,args);
    }
}
复制代码

2.5、SpringBootApplication注解使用

如果我们此时再创建一个包 com.zy.example.order.controller,新增OrderController.java代码:

复制代码
package com.zy.example.order.controller;

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

/**
 * @author zy
 * @since 2020-2-2
 */
@RestController
public class OrderController {
    @RequestMapping("/orderIndex")
    public  String orderIndex(){
        return "orderIndex";
    }
}
复制代码

此时需要修改扫包范围:

@ComponentScan(basePackages = {"com.zy.example.member.controller","com.zy.example.order.controller"})

当包很多的时候,这种写法无疑是麻烦的,此时我们可以使用@SpringBootApplication。

@SpringBootApplication 被 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解所修饰,换言之 Springboot 提供了统一的注解来替代以上三个注解。

扫包范围:在启动类上加上@SpringBootApplication注解,当前包下或者子包下所有的类都可以扫到。

由于App.Java文件位于包 com.zy.example.member.controller,因此使用@SpringBootApplication注解无法扫描到包 com.zy.example.order.controller,需要将App.java文件移动到包 com.zy.example中,并修改其代码如下:

复制代码
package com.zy.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 启动代码 * @author zy * @since 2020-2-2 */ @SpringBootApplication public class App { public static void main(String[] args){ //整个程序入口 启动Spring Boot项目 SpringApplication.run(App.class,args); } }
复制代码

三、Web开发

这里主要介绍一下在Spring Boot中如何访问静态页面,以及如何动态渲染Web页面,然而随着前后端分离技术的成熟,因此在Spring Boot中渲染Web页面基本不会再使用了。

3.1、静态资源访问

在我们开发Web应用的时候,需要引入大量的js、css、图片等静态资源。

Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:

  • /static
  • /public
  • /resources
  • /META-INF/resources

举例:我们可以在src/main/resources/目录下创建static,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/cjk.jpg。如能显示图片,配置成功。

3.2、渲染Web页面

在之前的示例中,我们都是通过@RestController来处理请求,所以返回的内容为json对象,那么如果需要渲染html页面的时候,要如何实现呢?

在动态HTML实现上Spring Boot仍然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板殷勤下,我们可以很快的上手开发动态网站。

Spring Boot提供了默认配置的模板引擎主要有以下几种:

  • Thymeleaf
  • FreeMarker
  • Velocity
  • Groovy
  • Mustache

Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性,具体可见后文:支持JSP的配置;
当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。

3.3、使用Freemarker模板引擎渲染Web视图

pom文件引入依赖包:

<!--   引入freemarker的依赖包   -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

在src/main/resources/创建一个templates文件夹,新建index.ftl文件:

复制代码
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
    ${name}
</body>
</html>
复制代码

创建包com.zy.example.template.controller,新建FTLIndexController.java:

复制代码
package com.zy.example.template.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

/**
 * 使用Freemarker模板引擎渲染web视图
 *
 * @author zy
 * @since 2020-2-3
 */
@Controller
public class FTLIndexController {
    @RequestMapping("/index")
    public String index(Map<String, Object> map) {
        map.put("name","美丽的天使...");
        return "index";
    }
}
复制代码

在src/main/resources下新建freemarker配置文件application.properties:

复制代码
## Freemarker 配置
##模版存放路径(默认为 classpath:/templates/)
spring.freemarker.template-loader-path=classpath:/templates/
##是否生成缓存,生成环境建议开启(默认为true)
spring.freemarker.cache=false
##编码
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
##content-type类型(默认为test/html)
spring.freemarker.content-type=text/html
## 设定所有request的属性在merge到模板的时候,是否要都添加到model中(默认为false)
spring.freemarker.expose-request-attributes=false
##设定所有HttpSession的属性在merge到模板的时候,是否要都添加到model中.(默认为false)
spring.freemarker.expose-session-attributes=false
##RequestContext属性的名称(默认为-)
spring.freemarker.request-context-attribute=request
##模板后缀(默认为.ftl)
spring.freemarker.suffix=.ftl
复制代码

运行程序,访问http://localhost:8080/index

3.4、使用jsp渲染Web视图

Spring Boot官方不推荐的jsp,因此这里就不过多介绍如何在Spring Boot中使用jsp,具体可以查找相关博客。

其中有两点需要注意:

  • 创建Spring Boot整合JSP,一定要为war类型项目,否则会找不到页面.;
  • 不要把JSP页面存放在resources/jsp下,因为该路径下不能被访问到;

3.5、全局捕获异常

创建包com.zy.example.error.controller,新建ErrorController.java文件:

复制代码
package com.zy.example.error.controller;

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

/**
 * 全局捕获异常
 *
 * @author zy
 * @since 2012-2-3
 */
@RestController
public class ErrorController {
    @RequestMapping("/getUser")
    public String getUser(@RequestParam int i){
        int j = 1/i;
        return "success" + j;
    }
}
复制代码

当我们访问http://localhost:8080/getUser?i=1,返回结果如下:

当我们访问http://localhost:8080/getUser?i=0,将会抛出异常:

针对这种情况,我们可以捕获异常,但是当有很多路由处理函数时,一一捕获效率很低。此时我们可以采用全局捕获异常、使用AOP技术,采用异常通知。

在包com.zy.example.error下,新建GlobalExceptionHandler.java,代码如下:

复制代码
package com.zy.example.error;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * 全局捕获异常:使用AOP技术,采用异常通知
 * 1、捕获返回json格式
 * 2、捕获返回页面
 *
 * @author zy
 * @since 2020-2-3
 */
@ControllerAdvice(basePackages = "com.zy.example")
public class GlobalExceptionHandler {
    //@ResponseBody:返回json格式
    //ModelAndView:返回视图页面
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Map<String,Object> errorResult(){
        //实际开发中 将错误记录在日志中
        Map<String,Object> errorResultMap = new HashMap<>();
        errorResultMap.put("errorCode","500");
        errorResultMap.put("errorMsg","系统错误");

        return errorResultMap;
    }
}
复制代码

再次访问http://localhost:8080/getUser?i=0,返回信息如下:

在上面代码中,我们使用到了如下注解:

  • @ExceptionHandler:表示拦截异常;
  • @ControllerAdvice 是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类,@ControllerAdvice 可以指定扫描范围,@ControllerAdvice 约定了几种可行的返回值:
  1. 如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换;
  2. 返回 String,表示跳到某个 view;
  3. 返回 ModelAndView;

四、日志管理

4.1、使用log4j2记录日志

在src/main/resources下新建log4j2.xml:

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://www.jianshu.com/p/8ded6531ef76 -->
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="WARN" monitorInterval="30">
    <!--先定义所有的appender-->
    <appenders>
        <!--这个输出控制台的配置-->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
        <File name="log" fileName="./logs/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="./logs/info.log"
                     filePattern="./logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileWarn" fileName="./logs/warn.log"
                     filePattern="./logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="./logs/error.log"
                     filePattern="./logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

    </appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="INFO">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>
</configuration>
复制代码

添加pom依赖:

复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <!-- 排除自带的logback依赖 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.2.2.RELASE</version>
        </dependency>
复制代码

修改GlobalExceptionHandler.java:

复制代码
package com.zy.example.error;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * 全局捕获异常:使用AOP技术,采用异常通知
 * 1、捕获返回json格式
 * 2、捕获返回页面
 *
 * @author zy
 * @since 2020-2-3
 */
@ControllerAdvice(basePackages = "com.zy.example")
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    //@ResponseBody:返回json格式
    //ModelAndView:返回视图页面
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Map<String,Object> errorResult(){
        //实际开发中 将错误记录在日志中
        Map<String,Object> errorResultMap = new HashMap<>();
        errorResultMap.put("errorCode","500");
        errorResultMap.put("errorMsg","系统错误");

        //打印错误消息
        logger.error("服务器内部错误");

        return errorResultMap;
    }
}
复制代码

再次访问http://localhost:8080/getUser?i=0,将会输出error信息,该信息日志会输出到当前项目./logs./error/error.log文件中:

2020-02-03 18:22 [http-nio-8080-exec-1] [com.zy.example.error.GlobalExceptionHandler] [ERROR] - 服务器内部错误

上面这种方法需要在需要打印日志的类中,创建一个日志写入器对象,然后在每个类中输出日志,那有没有一种统一处理日志的方式,当然有,下面我们将会介绍。

4.2、使用AOP统一处理Web请求日志

我们将所有控制器合并,要想使用AOP统一处理Web请求日志,首先需要添加aop依赖:

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

创建包com.zy.example.aop,新建WebLogAspect.java:

复制代码
package com.zy.example.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * 使用AOP统一处理Web请求日志
 *
 * @author zy
 * @since 2020-2-4
 */
@Aspect
@Component
public class WebLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    // 拦截包com.zy.example.controller下所有类中的所有方法
    @Pointcut("execution(public *  com.zy.example.controller.*.*(..))")
    public void webLog() {
    }

    /**
     * 使用AOP前置通知拦截请求参数信息
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容  一般最多记录半年,然后进行数据迁移、云备份
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String name = (String) enu.nextElement();
            logger.info("name:{},value:{}", name, request.getParameter(name));
        }
    }

    /**
     * 后置通知
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        logger.info("RESPONSE : " + ret);
    }
}
复制代码

运行程序,访问http://localhost:8080/getUser?i=1,将会打印日志信息:

2020-02-04 09:22:48 [http-nio-8080-exec-4] [com.zy.example.aop.WebLogAspect] [INFO] - URL : http://localhost:8080/getUser
2020-02-04 09:22:48 [http-nio-8080-exec-4] [com.zy.example.aop.WebLogAspect] [INFO] - HTTP_METHOD : GET
2020-02-04 09:22:48 [http-nio-8080-exec-4] [com.zy.example.aop.WebLogAspect] [INFO] - IP : 0:0:0:0:0:0:0:1
2020-02-04 09:22:48 [http-nio-8080-exec-4] [com.zy.example.aop.WebLogAspect] [INFO] - name:i,value:1
2020-02-04 09:22:48 [http-nio-8080-exec-4] [com.zy.example.aop.WebLogAspect] [INFO] - RESPONSE : success1

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(442)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示