Spring Boot项目搭建步骤(超详细)

2023-05-16

在 Spring Tools 4 for Eclipse 中依次选择 File->New->Maven Project,然后在出现的界面中按图 1 所示增加相关信息。

 


图 1 创建 maven 项目

完了上述操作之后,在 pom.xml 中添加 Spring Boot 的依赖,代码如下所示。

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.0.6.RELEASE</version>
  5. </parent>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. </dependencies>

编写启动类,代码如下所示。

  1. @SpringBootApplication
  2. public class App {
  3. public static void main(String[] args) {
  4. SpringApplication.run(App.class, args);
  5. }
  6. }

启动类使用了 @SpringBootApplication 注解,这个注解表示该类是一个 Spring Boot 应用。直接运行 App 类即可启动,启动成功后在控制台输出信息,默认端口是 8080,如图 2 所示。


图 2 Spring Boot启动成功

可以看到,我们只在 pom.xml 中引入了一个 Web 的 Starter,然后创建一个普通的 Java 类,一个 Main 方法就可以启动一个 Web 项目。

与之前的使用方式相比,这种方式简单很多。以前需要配置各种 Spring 相关的包,还需要配置 web.xml 文件,还需要将项目放入 Tomcat 中去执行,搭建项目的过程还特别容易出错,会出现各种 jar 包冲突。有了 Spring Boot 后这些问题都解决了。

我们之所以能够通过一个 Main 方法启动一个 Web 服务,是因为 Sprig Boot 中内嵌了 Tomcat,然后通过内嵌的 Tomcat 来提供服务。当然,我们也可以使用别的容器来替换 Tomcat,比如 Undertow 或 Jetty。

Spring Tools 4 for Eclipse 还为我们提供了更加便捷的项目创建方式,在 File->New 选项中有 Spring Starter Project,可以直接选择 Spring Boot 的版本以及需要依赖的第三方包,直接生成 Spring Boot 项目,不用再去手动配置 Maven 依赖。

这个功能和 https://start.spring.io/ 提供的是同一个功能,方便快速搭建 Spring Boot 项目脚手架。

编写第一个 REST 接口

本节将创建一个控制器,编写第一个 REST 接口,访问地址使用 /hello,代码如下所示。

  1. @RestController
  2. public class HelloController {
  3. @GetMapping("/hello")
  4. public String hello() {
  5. return "hello";
  6. }
  7. }

@RestController 是 @Controller 和 @ResponseBody 的组合注解,可以直接返回 Json 格式数据。

@GetMapping 其实就是 @RequestMapping(method=RequestMethod.GET),通过访问 http://localhost:8080/hello 可以看到输出的结果“hello”,如图 3 所示。


图 3 运行结果

读取配置文件

在以前的项目中我们主要在 XML 文件中进行框架配置,业务的相关配置会放在属性文件中,然后通过一个属性读取的工具类来读取配置信息。

在 Spring Boot 中我们不再需要使用这种方式去读取数据了。Spring Boot 中的配置通常放在 application.properties 中,读取配置信息非常方便,总共分为 3 种方式。

1)Environment

可以通过 Environment 的 getProperty 方法来获取想要的配置信息,代码如下所示。

  1. @RestController
  2. public class HelloController {
  3. // 注入对象
  4. @Autowired
  5. private Environment env;
  6. @GetMapping("/hello")
  7. public String hello() {
  8. // 读取配置
  9. String port = env.getProperty("server.port");
  10. return port;
  11. }
  12. }

2)@Value

可以注入具体的配置信息,代码如下所示。

  1. @RestController
  2. public class HelloController {
  3. // 注入配置
  4. @Value("${server.port}")
  5. private String port;
  6. @GetMapping("/hello")
  7. public String hello() {
  8. return port;
  9. }
  10. }

3)自定义配置类

prefix 定义配置的前缀,代码如下所示。

  1. @ConfigurationProperties(prefix = "cn.dandelioncloud")
  2. @Component
  3. public class MyConfig {
  4. private String name;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. }

读取配置的方法代码如下所示。

  1. @RestController
  2. public class HelloController {
  3. @Autowired
  4. private MyConfig myConfig;
  5. @GetMapping("/hello")
  6. public String hello() {
  7. return myConfig.getName();
  8. }
  9. }

定义配置 application.properties 的方法如下:

  1. cn.dandelioncloud.name=zhangsan

profiles 多环境配置

在平时的开发中,项目会被部署到测试环境、生产环境,但是每个环境的数据库地址等配置信息都是不一样的。通过 profile 来激活不同环境下的配置文件就能解决配置信息不一样的问题。在 Spring Boot 中可以通过 spring.profiles.active=dev 来激活不同环境下的配置。

可以定义多个配置文件,每个配置文件对应一个环境,格式为 application-环境.properties,如表 1 所示。

application.properties通用配置,不区分环境
application-dev.properties开发环境
application-test.properties测试环境
application-prod.properties生产环境

在开发环境中,可以通过修改 application.properties 中的 spring.profiles.active 的值来激活对应环境的配置,在部署的时候可以通过 java–jar xxx.jar—spring.profiles.active=dev 来指定使用对应的配置。

热部署

开发过程中经常会改动代码,此时若想看下效果,就不得不停掉项目然后重启。

对于 Spring Boot 项目来说,启动时间是非常快的,在微服务的架构下,每个服务只关注自己的业务,代码量也非常小,这个启动时间是可以容忍的。

对于那些臃肿的单体老项目,启动时间简直是浪费生命。虽然 Spring Boot 启动很快,但是我们还是要自己去重启。能不能做到有改动,它就会悄无声息地自己把改动的地方重新加载一遍?答案是肯定的,通过 spring-boot-devtools 就可以实现。

只需要添加 spring-boot-devtools 的依赖即可实现热部署功能,代码如下所示。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-devtools</artifactId>
  4. </dependency>

actuator 监控

Spring Boot 提供了一个用于监控和管理自身应用信息的模块,它就是 spring-boot-starter-actuator。该模块使用起来非常简单,只需要加入依赖即可,代码如下所示。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>

启动项目我们会发现在控制台输出的内容中增加了图 4 所示的信息。

图 4 所示的这些信息是 Actuator 模块提供的端点信息,具体如表 2 所示,通过访问这些端点我们可以得到很多监控信息。

比如,我们访问 /actuator/health 可以得到下面的信息:

  1. {
  2. "status": "UP"
  3. }


图 4 Spring Boot启动控制台输出

Http方法路径描述Http默认暴露
GET/actuator/conflgprops查看配置属性,包含默认配置false
GET/actuator/beans查看bean及其关系列表false
GET/actuator/heapdump打印线程栈false
GET/actuator/env查看所有环境变量false
GET/actuator/env/ {name}查看具体变量值true
GET/actuator/health查看应用健康指标true
GET/actuator/info查看应用信息false
GET/actuator/mappings查看所有 URL 映射false
GET/actuator/metrics查看应用基本指标false
GET/actuator/metrics/{name}查看具体指标false
POST/actuator/shutdown关闭应用false
GET/actuator/httptrace查看基本追踪信息false
GET/actuator/loggers显示应用程序中 loggers 配置false
GET/actuator/scheduledtasks显示定时任务false

UP 表示当前应用处于健康状态,如果是 DOWN 就表示当前应用不健康。增加下面的配置可以让一些健康信息的详情也显示出来:

  1. management.endpoint.health.show-details=ALWAYS

再次访问 /actuator/health,就可以得到健康状态的详细信息:

  1. {
  2. "status": "UP",
  3. "diskSpace": {
  4. "status": "UP",
  5. "total": 491270434816,
  6. "free": 383870214144,
  7. "threshold": 10485760
  8. }
  9. }

大部分端点默认都不暴露出来,我们可以手动配置需要暴露的端点。如果需要暴露多个端点,可以用逗号分隔,如下所示:

  1. management.endpoints.web.exposure.include=configprops,beans

如果想全部端点都暴露的话直接配置成下面的方式:

  1. management.endpoints.web.exposure.include=*

关于这些监控的信息不再赘述,大家可以自行了解。后面我们会介绍如何使用 Spring Boot Admin 在页面上更加直观地展示这些信息,目前都是 Json 格式的数据,不方便查看。

自定义 actuator 端点

在很多场景下,我们需要自定义一些规则来判断应用的状态是否健康,可以采用自定义端点的方式来满足多样性的需求。如果我们只是需要对应用的健康状态增加一些其他维度的数据,可以通过继承 AbstractHealthIndicator 来实现自己的业务逻辑。代码如下所示。

  1. @Component
  2. public class UserHealthIndicator extends AbstractHealthIndicator {
  3. @Override
  4. protected void doHealthCheck(Builder builder) throws Exception {
  5. builder.up().withDetail("status", true);
  6. // builder.down().withDetail("status", false);
  7. }
  8. }

通过 up 方法指定应用的状态为健康,down 方法指定应用的状态为不健康。withDetail 方法用于添加一些详细信息。访问 /actuator/health,可以得到我们自定义的健康状态的详细信息:

  1. {
  2. "status": "UP",
  3. "details": {
  4. "user": {
  5. "status": "UP",
  6. "details": {
  7. "status": true
  8. }
  9. },
  10. "diskSpace": {
  11. "status": "UP",
  12. "details": {
  13. "total":
  14. 249795969024,
  15. "free": 7575375872,
  16. "threshold": 10485760
  17. }
  18. }
  19. }
  20. }

上面我们是在框架自带的 health 端点中进行扩展,还有一种需求是完全开发一个全新的端点,比如查看当前登录的用户信息的端点。自定义全新的端点很简单,通过 @Endpoint 注解就可以实现。代码如下所示。

  1. @Component
  2. @Endpoint(id = "user")
  3. public class UserEndpoint {
  4. @ReadOperation
  5. public List<Map<String, Object>> health() {
  6. List<Map<String, Object>> list = new ArrayList<>();
  7. Map<String, Object> map = new HashMap<>();
  8. map.put("userId", 1001);
  9. map.put("userName", "zhangsan");
  10. list.add(map);
  11. return list;
  12. }
  13. }

访问 /actuator/user 可以看到返回的用户信息如下:

  1. [
  2. {
  3. "userName": "zhangsan",
  4. "userId": 1001
  5. }
  6. ]

统一异常处理

对于接口的定义,我们通常会有一个固定的格式,比如:

  1. {
  2. "status": true,
  3. "code": 200,
  4. "message": null,
  5. "data": [
  6. {
  7. "id": "101",
  8. "name": "jack"
  9. },
  10. {
  11. "id": "102",
  12. "name": "jason"
  13. }
  14. ]
  15. }

但是,如果调用方在请求我们的 API 时把接口地址写错了,就会得到一个 404 错误:

  1. {
  2. "timestamp": 1492063521109,
  3. "status": 404,
  4. "error": "Not Found",
  5. "message": "No message available",
  6. "path": "/rest11/auth"
  7. }

后端服务会告诉我们哪个地址没找到,其实也挺友好。但是因为我们上面自定义的数据格式跟下面的不一致,所以当用户拿到这个返回的时候是无法识别的,其中最明显的是 status 字段。

我们自定义的是 boolean 类型,用来表示请求是否成功,这里返回的就是 Http 的状态码,所以我们需要在发生这种系统错误时也能返回我们自定义的那种格式,那就要定义一个异常处理类(代码如下所示),通过这个类既可以返回统一的格式,也可以统一记录异常日志。

  1. @ControllerAdvice
  2. public class GlobalExceptionHandler {
  3. private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
  4. @ExceptionHandler(value = Exception.class)
  5. @ResponseBody
  6. public ResponseData defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
  7. logger.error("", e);
  8. ResponseData r = new ResponseData();
  9. r.setMessage(e.getMessage());
  10. if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) {
  11. r.setCode(404);
  12. } else {
  13. r.setCode(500);
  14. }
  15. r.setData(null);
  16. r.setStatus(false);
  17. return r;
  18. }
  19. }

ResponseData 是我们返回格式的实体类,其发生错误时也会被捕获到,然后封装好返回格式并返回给调用方。最后关键的一步是,在 Spring Boot 的配置文件中加上如下代码所示配置。

  1. # 出现错误时, 直接抛出异常
  2. spring.mvc.throw-exception-if-no-handler-found=true
  3. # 不要为我们工程中的资源文件建立映射
  4. spring.resources.add-mappings=false

然后当我们调用一个不存在的接口时,返回的错误信息就是我们自定义的那种格式了:

  1. {
  2. "status": false, "code": 404,
  3. "message": "No handler found for GET /rest11/auth", "data": null
  4. }

最后贴上 ResponseData 的定义,代码如下所示。

  1. public class ResponseData {
  2. private Boolean status = true;
  3. private int code = 200;
  4. private String message;
  5. private Object data;
  6. // get set ...
  7. }

异步执行

异步调用就是不用等待结果的返回就执行后面的逻辑;同步调用则需要等待结果再执行后面的逻辑。

通常我们使用异步操作时都会创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下所示。

  1. ExecutorService executorService = Executors.newFixedThreadPool(10);
  2. executorService.execute(() -> {
  3. try {
  4. // 业务逻辑
  5. } catch (Exception e) {
  6. e.printStackTrace();
  7. } finally {
  8. }
  9. });

这种方式尽管使用了 Java 的 Lambda,但看起来没那么优雅。在 Spring 中有一种更简单的方式来执行异步操作,只需要一个 @Async 注解即可,代码如下所示。

  1. @Async
  2. public void saveLog() {
  3. System.err.println(Thread.currentThread().getName());
  4. }

我们可以直接在 Controller 中调用这个业务方法,它就是异步执行的,会在默认的线程池中去执行。需要注意的是,一定要在外部的类中去调用这个方法,如果在本类调用则不起作用,比如 this.saveLog()。最后在启动类上开启异步任务的执行,添加 @EnableAsync 即可。

另外,关于执行异步任务的线程池我们也可以自定义,首先我们定义一个线程池的配置类,用来配置一些参数,具体代码如下所示。

  1. @Configuration
  2. @ConfigurationProperties(prefix = "spring.task.pool")
  3. public class TaskThreadPoolConfig {
  4. // 核心线程数
  5. private int corePoolSize = 5;
  6. // 最大线程数
  7. private int maxPoolSize = 50;
  8. // 线程池维护线程所允许的空闲时间
  9. private int keepAliveSeconds = 60;
  10. // 队列长度
  11. private int queueCapacity = 10000;
  12. // 线程名称前缀
  13. private String threadNamePrefix = "FSH-AsyncTask-";
  14. // get set ...
  15. }

然后我们重新定义线程池的配置,代码如下所示。

  1. @Configuration
  2. public class AsyncTaskExecutePool implements AsyncConfigurer {
  3. private Logger logger = LoggerFactory.getLogger(AsyncTaskExecutePool.class);
  4. @Autowired
  5. private TaskThreadPoolConfig config;
  6. @Override
  7. public Executor getAsyncExecutor() {
  8. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  9. executor.setCorePoolSize(config.getCorePoolSize());
  10. executor.setMaxPoolSize(config.getMaxPoolSize());
  11. executor.setQueueCapacity(config.getQueueCapacity());
  12. executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
  13. executor.setThreadNamePrefix(config.getThreadNamePrefix());
  14. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
  15. executor.initia lize();
  16. return executor;
  17. }
  18. @Override
  19. public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
  20. // 异步任务中异常处理
  21. return new AsyncUncaughtExceptionHandler() {
  22. @Override
  23. public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
  24. logger.error("==========================" + arg0.getMessage() + "=======================", arg0);
  25. logger.error("exception method:" + arg1.getName());
  26. }
  27. };
  28. }
  29. }

配置完之后我们的异步任务执行的线程池就是我们自定义的了,我们可以在属性文件里面配置线程池的大小等信息,也可以使用默认的配置:

  1. spring.task.pool.maxPoolSize=100

最后讲一下线程池配置的拒绝策略。当我们的线程数量高于线程池的处理速度时,任务会被缓存到本地的队列中。队列也是有大小的,如果超过了这个大小,就需要有拒绝的策略,不然就会出现内存溢出。目前支持两种拒绝策略:

  • AbortPolicy:直接抛出 java.util.concurrent.RejectedExecutionException 异常。
  • CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,这样可以有效降低向线程池内添加任务的速度。

建议大家用 CallerRunsPolicy 策略,因为当队列中的任务满了之后,如果直接抛异常,那么这个任务就会被丢弃。如果是 CallerRunsPolicy 策略,则会用主线程去执行,也就是同步执行,这样操作最起码任务不会被丢弃。

随机端口

在实际的开发过程中,每个项目的端口都是定好的,通过 server.port 可以指定端口。

当一个服务想要启动多个实例时,就需要改变端口,特别是在我们后面进行 Spring Cloud 学习的时候,服务都会注册到注册中心里去,为了能够让服务随时都可以扩容,在服务启动的时候能随机生成一个可以使用的端口是最好不过的。

在 Spring Boot 中,可以通过 ${random} 来生成随机数字,我们可以这样使用:

  1. server.port=${random.int[2000,8000]}

通过 random.int 方法,指定随机数的访问,生成一个在 2000 到 8000 之间的数字,这样每次启动的端口就都不一样了。

其实上面的方法虽然能够达到预期的效果,但是也会存在一些问题:如果这个端口已经在使用了,那么启动必然会报错。所以我们可以通过代码的方式来随机生成一个端口,然后检测是否被使用,这样就能生成一个没有被使用的端口。

编写一个启动参数设置类,代码如下所示。

  1. public class StartCommand {
  2. private Logger logger = LoggerFactory.getLogger(StartCommand.class);
  3. public StartCommand(String[] args) {
  4. Boolean isServerPort = false;
  5. String serverPort = "";
  6. if (args != null) {
  7. for (String arg : args) {
  8. if (StringUtils.hasText(arg) && arg.startsWith("--server.port")) {
  9. isServerPort = true;
  10. serverPort = arg;
  11. break;
  12. }
  13. }
  14. }
  15. // 没有指定端口, 则随机生成一个可用的端口
  16. if (!isServerPort) {
  17. int port = ServerPortUtils.getAvailablePort();
  18. logger.info("current server.port=" + port);
  19. System.setProperty("server.port", String.valueOf(port));
  20. } else {
  21. logger.info("current server.port=" + serverPort.split("=")[1]);
  22. System.setProperty("server.port", serverPort.split("=")[1]);
  23. }
  24. }
  25. }

通过对启动参数进行遍历判断,如果有指定启动端口,后续就不自动生成了;如果没有指定,就通过 ServerPortUtils 获取一个可以使用的端口,然后设置到环境变量中。在 application.properties 中通过下面的方式获取端口:

  1. server.port=${server.port}

关于获取可用端口的代码如下所示。

  1. public static int getAvailablePort() {
  2. int max = 65535;
  3. int min = 2000;
  4. Random random = new Random();
  5. int port = random.nextInt(max)%(max-min+1) + min;
  6. boolean using = NetUtils.isLoclePortUsing(port);
  7. if (using) {
  8. return getAvailablePort();
  9. } else {
  10. return port;
  11. }
  12. }

获取可用端口的主要逻辑是指定一个范围,然后生成随机数字,最后通过 NetUtils 来检查端口是否可用。如果获取到可用的端口则直接返回,没有获取到可用的端口则执行回调逻辑,重新获取。检测端口是否可用主要是用 Socket 来判断这个端口是否可以被链接。

最后在启动类中调用端口即可使用,代码如下所示。

  1. public class FshHouseServiceApplication {
  2. public static void main(String[] args) {
  3. // 启动参数设置, 比如自动生成端口
  4. new StartCommand(args);
  5. SpringApplication.run(FshHouseServiceApplication.class, args);
  6. }
  7. }

编译打包

传统的 Web 项目在部署的时候,是编译出一个 war 包放到 Tomcat 的 webapps 目录下。而在 Spring Boot 构建的 Web 项目中则打破了这一传统部署的方式,它采用更加简单的内置容器方式来部署应用程序,只需要将应用编译打包成一个 jar 包,直接可以通过 java–jar 命令启动应用。

在项目的 pom.xml 中增加打包的 Maven 插件,代码如下所示。

  1. <build>
  2. <plugins>
  3. <!-- 打包插件 -->
  4. <plugin>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-maven-plugin</artifactId>
  7. <configuration>
  8. <executable>true</executable>
  9. <mainClass>cn.dandelioncloud.spring_boot_example.App</mainClass>
  10. </configuration>
  11. </plugin>
  12. <!-- 编译插件, 指定JDK版本 -->
  13. <plugin>
  14. <groupId>org.apache.maven.plugins</groupId>
  15. <artifactId>maven-compiler-plugin</artifactId>
  16. <configuration>
  17. <source>1.8</source>
  18. <target>1.8</target>
  19. </configuration>
  20. </plugin>
  21. </plugins>
  22. </build>

mainClass 配置的是我们的启动入口类,配置完成后可以通过 Maven 的 mvn clean package 命令进行编译打包操作。编译完成后在 target 目录下会生成对应的 jar 包,部署的时候直接调用 java–jar xx.jar 即可启动应用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot项目搭建步骤(超详细) 的相关文章

随机推荐

  • Opencv中的Mat类使用方法总结

    此文章转载自 xff1a http lib csdn net article opencv 42000 今天在看Opencv的SIFT源码 xff0c 至于有关于SIFT算法的博客还没有写完 xff0c 等着我把源码看完再一起写完吧 之前用
  • 快速排序-java版(快排)

    算法本质 快排属于交换排序 xff0c 快排的基本思想是基于分治的 快排的本质就是通过一趟排序将基准数排到最终的位置 即以基准数为中心将待排序的序列划分成两个子序列 xff0c 一个子序列是基准数前面的数 xff0c 都比基准数小 xff1
  • Ubuntu 16.04安装chrome稳定版

    1 打开终端 xff08 Ctrl 43 Alt 43 T xff09 xff0c 输入以下命令 xff1a sudo wget https repo fdzh org chrome google chrome list P etc apt
  • 【建议收藏】保姆级教程 - 图解Windows10+优麒麟双系统安装

    为防止超速翻车 xff0c 建议通读全文后再进行操作 xff08 此处双系统以 Windows 10 43 优麒麟 20 04 LTS Pro 为例 xff0c 其他版本的系统仅供参考 xff09 01 安装前的准备 四小步 第一步 xff
  • Linux文件系统--文件类型

    Linux中一切都是文件 xff0c 文件类型有多种 xff0c 使用ls l命令可以查看文件属性 xff0c 所显示结果的第一列的第一个字符用来表示文件类型 xff0c 如下 xff1a 1 普通文件 第一列第一个字符为 的文件为普通文件
  • Windows Terminal 快速配置 oh-my-posh

    背景 想美化下windows terminal xff0c 选择了oh my posh 网上的文章有点多 xff0c 加上官方的教程对初次使用着并不是太友好 xff0c 所以自己快速摸索了 记录下过程 步骤 1 xff0c 安装oh my
  • SVN彻底删除某版本的方法

    如果出现了提交失误 xff0c 想从服务器端彻底删除某版本 xff0c 可以这么做 在服务器端的Repository RepoName db revs 0和 db revprops 0中删除对应的版本号 xff0c 此时再update会出现
  • ZEMAX | 使用点扩散函数的衍射极限成像系统的分辨率

    ZEMAX 使用点扩散函数的衍射极限成像系统的分辨率 成像系统 xff08 例如显微镜 xff09 的衍射极限分辨率可以通过不同方式表征 在本文中 xff0c 我建议使用在 OpticStudio 中计算的点扩散函数 PSF 来客观衡量这些
  • 荐书 | 从启蒙到进阶,值得推荐的五本少儿编程

    据小木对身边的人了解 xff0c 好像码农们都有这么一个愿望 xff1a 等我有孩子了 xff0c 我一定教我的孩子学编程 玩游戏玩自己设计的才酷 xff01 看着一个个码农爸爸憧憬着美好的愿景 xff0c 小木恨不得马上帮他们实现这个愿望
  • 在浏览器中输入一个网址后,发生了什么?

    此文章转载自 xff1a https www cnblogs com SarahLiu p 5954832 html 这是面试中一道非常经典的问题 当你在浏览器中输入一个网址 xff0c 浏览器的处理过程如下 xff1a 第一步 浏览器查找
  • Banner基本使用 2.1.0

    Step 1 依赖banner Gradle dependencies compile 39 com youth banner banner 2 1 0 39 Step 2 添加权限到你的 AndroidManifest xml lt if
  • eclipse控制台变动难调整

  • 苹果cms详细安装方法

    做影视网站的站长对苹果cms是相当熟悉的 xff0c 毕竟这套系统实在太好用了 xff0c 使它一直火到了今天 xff01 今天小编就带着刚接触到本套程序的大家用它来搭建一次影视视频网站 xff01 程序运行环境 Apache 43 PHP
  • MySQL的版本以及版本号

    针对不同的用户 xff0c MySQL 分为两个版本 xff1a MySQL Community Server xff08 社区版 xff09 xff1a 该版本完全免费 xff0c 但是官方不提供技术支持 MySQL Enterprise
  • MySQL配置教程(图解版)

    配置 MySQL 数据库有两种比较常见的方式 xff0c 分别是使用配置向导和手动更改 xff0c 下面我们来分别介绍一下这两种方式 使用配置向导 步骤 1 xff1a MySQL 安装完成之后 xff0c 进行配置信息的确认 xff0c
  • MySQL常用运算符详解

    MySQL 数据库中的表结构确立后 xff0c 表中的数据代表的意义就已经确定 而通过 MySQL 运算符进行运算 xff0c 就可以获取到表结构以外的另一种数据 例如 xff0c 学生表中存在一个 birth 字段 xff0c 这个字段表
  • Java 文档注释

    Java 支持三种注释方式 前两种分别是 和 xff0c 第三种被称作说明注释 xff0c 它以 开始 xff0c 以 结束 说明注释允许你在程序中嵌入关于程序的信息 你可以使用 javadoc 工具软件来生成信息 xff0c 并输出到HT
  • JSP开发环境搭建(Tomcat的安装和配置)

    使用 JSP 开发程序 xff0c 需要具备对应的运行环境 xff1a Web 浏览器 Web 服务器 JDK 开发工具包 数据库 xff08 MySQL SQL Server 等 xff09 下面以 Windows 操作系统为平台介绍 J
  • JS字符串替换(使用replace()方法)

    replace 方法的第二个参数可以使用函数 xff0c 当匹配时会调用该函数 xff0c 函数的返回值将作为替换文本使用 xff0c 同时函数可以接收以 为前缀的特殊字符 xff0c 用来引用匹配文本的相关信息 约定字符串说明 1 2 9
  • Spring Boot项目搭建步骤(超详细)

    在 Spring Tools 4 for Eclipse 中依次选择 File gt New gt Maven Project xff0c 然后在出现的界面中按图 1 所示增加相关信息 图 1 创建 maven 项目 完了上述操作之后 xf