欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot使用CommandLineRunner接口完成資源初始化方式

 更新時間:2023年02月13日 10:43:22   作者:思影影思  
這篇文章主要介紹了SpringBoot使用CommandLineRunner接口完成資源初始化方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

1 簡介

1.1 應(yīng)用場景

在應(yīng)用服務(wù)啟動時,需要在所有Bean生成之后,加載一些數(shù)據(jù)和執(zhí)行一些應(yīng)用的初始化。

例如:刪除臨時文件,清楚緩存信息,讀取配置文件,數(shù)據(jù)庫連接,這些工作類似開機自啟動的概念,CommandLineRunner、ApplicationRunner 接口是在容器啟動成功后的最后一步回調(diào)(類似開機自啟動)。

1.2 CommandLineRunner接口

CommandLineRunner源碼實現(xiàn)如下:

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming main method arguments
    * @throws Exception on error
    */
   void run(String... args) throws Exception;

}

對該接口的注釋可以看到如下的含義:

該接口用來指明:當(dāng)一個bean包含在SpringApplication內(nèi),該bean就應(yīng)當(dāng)執(zhí)行??梢栽谙嗤膽?yīng)用上下文定義多個這樣的bean。多個bean的先后執(zhí)行順序使用@Order注解確定。

1.3 ApplicationRunner接口

ApplicationRunner接口源碼定義如下:

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see CommandLineRunner
 */
@FunctionalInterface
public interface ApplicationRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming application arguments
    * @throws Exception on error
    */
   void run(ApplicationArguments args) throws Exception;

}

在對該接口的注釋中,可以看到兩個接口的應(yīng)用場景,甚至注釋都是完全一樣的。

唯一的區(qū)別是接口中的函數(shù)run的參數(shù),一個是與main函數(shù)同樣的(String[] args),而另外一個是ApplicationArgumens類型。

在一般情況下,開發(fā)時是不需要添加命令行參數(shù)的,因此兩個接口的區(qū)別對于這樣的場景也就完全一樣了。

但如果真的需要類型–foo=bar的option arguments,為了方便起見,可以使用ApplicationRunner來讀取類似的參數(shù)。

1.4 @Order注解

Order注解的源碼實現(xiàn)如下:

package org.springframework.core.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.Ordered;

/**
 * {@code @Order} defines the sort order for an annotated component.
 *
 * <p>The {@link #value} is optional and represents an order value as defined in the
 * {@link Ordered} interface. Lower values have higher priority. The default value is
 * {@code Ordered.LOWEST_PRECEDENCE}, indicating lowest priority (losing to any other
 * specified order value).
 *
 * <p><b>NOTE:</b> Since Spring 4.0, annotation-based ordering is supported for many
 * kinds of components in Spring, even for collection injection where the order values
 * of the target components are taken into account (either from their target class or
 * from their {@code @Bean} method). While such order values may influence priorities
 * at injection points, please be aware that they do not influence singleton startup
 * order which is an orthogonal concern determined by dependency relationships and
 * {@code @DependsOn} declarations (influencing a runtime-determined dependency graph).
 *
 * <p>Since Spring 4.1, the standard {@link javax.annotation.Priority} annotation
 * can be used as a drop-in replacement for this annotation in ordering scenarios.
 * Note that {@code @Priority} may have additional semantics when a single element
 * has to be picked (see {@link AnnotationAwareOrderComparator#getPriority}).
 *
 * <p>Alternatively, order values may also be determined on a per-instance basis
 * through the {@link Ordered} interface, allowing for configuration-determined
 * instance values instead of hard-coded values attached to a particular class.
 *
 * <p>Consult the javadoc for {@link org.springframework.core.OrderComparator
 * OrderComparator} for details on the sort semantics for non-ordered objects.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 2.0
 * @see org.springframework.core.Ordered
 * @see AnnotationAwareOrderComparator
 * @see OrderUtils
 * @see javax.annotation.Priority
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {

   /**
    * The order value.
    * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.
    * @see Ordered#getOrder()
    */
   int value() default Ordered.LOWEST_PRECEDENCE;

}

可以看到該注解的作用主要是用來定義被注解的組件的排序順序。

注意:Lower values have higher priority。值越小越先執(zhí)行。

1.5 CommandLineRunner和ApplicationRunner區(qū)別

從上面的分析可以看出,CommandLineRunner和ApplicationRunner接口的作用是完全一致的,唯一不同的則是接口中待實現(xiàn)的run方法,其中CommandLineRunner的run方法參數(shù)類型與main一樣是原生的String[] 類型,而ApplicationRunner的run方法參數(shù)類型為ApplicationArguments類型。

ApplicationArguments類型源碼定義如下:

package org.springframework.boot;

import java.util.List;
import java.util.Set;

/**
 * Provides access to the arguments that were used to run a {@link SpringApplication}.
 * 提供用來運行一個SpringApplication的參數(shù)。
 * @author Phillip Webb
 * @since 1.3.0
 */
public interface ApplicationArguments {

   /**
    * Return the raw unprocessed arguments that were passed to the application.
    * @return the arguments
    */
   String[] getSourceArgs();

   /**
    * Return the names of all option arguments. For example, if the arguments were
    * "--foo=bar --debug" would return the values {@code ["foo", "debug"]}.
    * @return the option names or an empty set
    */
   Set<String> getOptionNames();

   /**
    * Return whether the set of option arguments parsed from the arguments contains an
    * option with the given name.
    * @param name the name to check
    * @return {@code true} if the arguments contain an option with the given name
    */
   boolean containsOption(String name);

   /**
    * Return the collection of values associated with the arguments option having the
    * given name.
    * <ul>
    * <li>if the option is present and has no argument (e.g.: "--foo"), return an empty
    * collection ({@code []})</li>
    * <li>if the option is present and has a single value (e.g. "--foo=bar"), return a
    * collection having one element ({@code ["bar"]})</li>
    * <li>if the option is present and has multiple values (e.g. "--foo=bar --foo=baz"),
    * return a collection having elements for each value ({@code ["bar", "baz"]})</li>
    * <li>if the option is not present, return {@code null}</li>
    * </ul>
    * @param name the name of the option
    * @return a list of option values for the given name
    */
   List<String> getOptionValues(String name);

   /**
    * Return the collection of non-option arguments parsed.
    * @return the non-option arguments or an empty list
    */
   List<String> getNonOptionArgs();

}

在這里插入圖片描述

ApplicaitonArguments類型之間的關(guān)系如下:

在這里插入圖片描述

1.5.1 option-argument和non-option arguments

在這里插入圖片描述

參見命令解釋中option和non-option參數(shù)

1.5.2 SimpleCommandLineArgsParser

由于SimpleCommandLineArgsParser的功能是ApplicationArguments實現(xiàn)的的核心,簡單看下該類實現(xiàn)的源碼:

package org.springframework.core.env;

/**
 * Parses a {@code String[]} of command line arguments in order to populate a
 * {@link CommandLineArgs} object.
 *
 * <h3>Working with option arguments</h3>
 * Option arguments must adhere to the exact syntax:
 * <pre class="code">--optName[=optValue]</pre>
 * That is, options must be prefixed with "{@code --}", and may or may not specify a value.
 * If a value is specified, the name and value must be separated <em>without spaces</em>
 * by an equals sign ("=").
 *
 * <h4>Valid examples of option arguments</h4>
 * <pre class="code">
 * --foo
 * --foo=bar
 * --foo="bar then baz"
 * --foo=bar,baz,biz</pre>
 *
 * <h4>Invalid examples of option arguments</h4>
 * <pre class="code">
 * -foo
 * --foo bar
 * --foo = bar
 * --foo=bar --foo=baz --foo=biz</pre>
 *
 * <h3>Working with non-option arguments</h3>
 * Any and all arguments specified at the command line without the "{@code --}" option
 * prefix will be considered as "non-option arguments" and made available through the
 * {@link CommandLineArgs#getNonOptionArgs()} method.
 *
 * @author Chris Beams
 * @since 3.1
 */
class SimpleCommandLineArgsParser {

   /**
    * Parse the given {@code String} array based on the rules described {@linkplain
    * SimpleCommandLineArgsParser above}, returning a fully-populated
    * {@link CommandLineArgs} object.
    * @param args command line arguments, typically from a {@code main()} method
    */
   public CommandLineArgs parse(String... args) {
      CommandLineArgs commandLineArgs = new CommandLineArgs();
      for (String arg : args) {
         if (arg.startsWith("--")) {
            String optionText = arg.substring(2, arg.length());
            String optionName;
            String optionValue = null;
            if (optionText.contains("=")) {
               optionName = optionText.substring(0, optionText.indexOf('='));
               optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
            }
            else {
               optionName = optionText;
            }
            if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
               throw new IllegalArgumentException("Invalid argument syntax: " + arg);
            }
            commandLineArgs.addOptionArg(optionName, optionValue);
         }
         else {
            commandLineArgs.addNonOptionArg(arg);
         }
      }
      return commandLineArgs;
   }

}

在程序執(zhí)行過程中,SimpleCommandLineArgsParser會把程序的參數(shù)分解成option arguments和nonoption arguments,然后放入CommandLineArgs,

在這里插入圖片描述

CommandLineArgs類的實現(xiàn)如下:

package org.springframework.core.env;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.lang.Nullable;

/**
 * A simple representation of command line arguments, broken into "option arguments" and
 * "non-option arguments".
 *
 * @author Chris Beams
 * @since 3.1
 * @see SimpleCommandLineArgsParser
 */
class CommandLineArgs {

   private final Map<String, List<String>> optionArgs = new HashMap<>();
   private final List<String> nonOptionArgs = new ArrayList<>();

   /**
    * Add an option argument for the given option name and add the given value to the
    * list of values associated with this option (of which there may be zero or more).
    * The given value may be {@code null}, indicating that the option was specified
    * without an associated value (e.g. "--foo" vs. "--foo=bar").
    */
   public void addOptionArg(String optionName, @Nullable String optionValue) {
      if (!this.optionArgs.containsKey(optionName)) {
         this.optionArgs.put(optionName, new ArrayList<>());
      }
      if (optionValue != null) {
         this.optionArgs.get(optionName).add(optionValue);
      }
   }

   /**
    * Return the set of all option arguments present on the command line.
    */
   public Set<String> getOptionNames() {
      return Collections.unmodifiableSet(this.optionArgs.keySet());
   }

   /**
    * Return whether the option with the given name was present on the command line.
    */
   public boolean containsOption(String optionName) {
      return this.optionArgs.containsKey(optionName);
   }

   /**
    * Return the list of values associated with the given option. {@code null} signifies
    * that the option was not present; empty list signifies that no values were associated
    * with this option.
    */
   @Nullable
   public List<String> getOptionValues(String optionName) {
      return this.optionArgs.get(optionName);
   }

   /**
    * Add the given value to the list of non-option arguments.
    */
   public void addNonOptionArg(String value) {
      this.nonOptionArgs.add(value);
   }

   /**
    * Return the list of non-option arguments specified on the command line.
    */
   public List<String> getNonOptionArgs() {
      return Collections.unmodifiableList(this.nonOptionArgs);
   }

}

2 CommandLineRunner完成資源初始化

2.1 背景介紹

在項目運行的過程中,項目會事先訂閱一些關(guān)注的事件,大的方向分為門禁事件和監(jiān)控點事件,其中上報上來的門禁事件的基本信息為門禁點信息,而不是門禁設(shè)備的唯一標(biāo)識,為了解析的方便,需要把上報上來的門禁點事件和門禁設(shè)備唯一標(biāo)識、IP信息關(guān)聯(lián)起來,這表示,在項目啟動之后,當(dāng)所有bean都完成了加載,需要在項目開始提供其他REST服務(wù)之前,把門禁點到門禁設(shè)備唯一標(biāo)識、IP等信息關(guān)聯(lián)起來。

而這個關(guān)聯(lián)的獲取,需要類似開機自啟動的功能一樣,需要項目一啟動,就獲取這個關(guān)聯(lián)。

其中,獲取所有門禁設(shè)備的基本信息可以通過AcsDeviceController獲取,而所有門禁點信息的獲取通過AcsDoorController獲取。

2.2 數(shù)據(jù)類型關(guān)系

調(diào)用獲取所有門禁設(shè)備信息,可以獲得形似如下的數(shù)據(jù):

{
    "msg": "success",
    "code": "0",
    "data": {
        "list": [
            {
                "regionIndexCode": "a6745925-0415-4853-9815-bb9707e2ad8b",
                "acsDevTypeCode": "201933568",
                "createTime": "2019-04-11T20:10:16.184+08:00",
                "acsDevTypeDesc": "DS-K1T604MF",
                "acsDevName": "門禁一體機1",
                "acsDevIndexCode": "71a9ea67d58a43db8c5dadfe2197a4db",
                "updateTime": "2019-04-11T20:18:01.683+08:00",
                "acsDevIp": "192.168.1.103",
                "acsDevPort": "8000",
                "treatyType": "hiksdk_net"
            },
            {
                "regionIndexCode": "a6745925-0415-4853-9815-bb9707e2ad8b",
                "acsDevTypeCode": "201933568",
                "createTime": "2019-04-11T20:12:06.137+08:00",
                "acsDevTypeDesc": "DS-K1T604MF",
                "acsDevName": "門禁一體機3",
                "acsDevIndexCode": "13891ae9f6454782a208504e72ba2ad8",
                "updateTime": "2019-04-11T20:12:07.876+08:00",
                "acsDevIp": "192.168.1.105",
                "acsDevPort": "8000",
                "treatyType": "hiksdk_net"
            }
        ]
    }
}

可以看到所有的門禁設(shè)備均包含設(shè)備的唯一標(biāo)識acsDevIndexCode、acsDevName門禁設(shè)備名稱、門禁設(shè)備IP地址acsDevIp,門禁設(shè)備端口acsDevPort。

而獲取所有的門禁點接口可以獲取如下的內(nèi)容:

{
    "msg": "success",
    "code": "0",
    "data": {
        "list": [
            {
                "regionIndexCode": "a6745925-0415-4853-9815-bb9707e2ad8b",
                "channelNo": "1",
                "createTime": "2019-04-11T20:12:06.166+08:00",
                "doorName": "門禁一體機3_門1",
                "doorIndexCode": "a87022481f8242b29a4bf35a57edc004",
                "acsDevIndexCode": "13891ae9f6454782a208504e72ba2ad8",
                "channelType": "door",
                "updateTime": "2019-04-11T20:12:16.012+08:00",
                "doorNo": "1"
            },
            {
                "regionIndexCode": "a6745925-0415-4853-9815-bb9707e2ad8b",
                "channelNo": "1",
                "createTime": "2019-04-11T20:10:17.826+08:00",
                "doorName": "門禁一體機1_門1",
                "doorIndexCode": "139dcaecc5ba4b9fb97889c2f2234e79",
                "acsDevIndexCode": "71a9ea67d58a43db8c5dadfe2197a4db",
                "channelType": "door",
                "updateTime": "2019-04-11T20:12:16.012+08:00",
                "doorNo": "1"
            }
        ]
    }
}

可以看到獲取到的門禁點信息,會同時包含門禁設(shè)備的唯一標(biāo)識字段,因此可以根據(jù)該字段門禁點唯一標(biāo)識獲得門禁點到門禁設(shè)備基本信息的映射。

當(dāng)系統(tǒng)訂閱了相關(guān)的事件之后,可以收到的事件報文格式如下:

{
	"method": "OnEventNotify",
	"params": {
		"ability": "event_acs",
		"events": [{
			"data": {
				"ExtAccessChannel": 0,
				"ExtEventAlarmInID": 0,
				"ExtEventAlarmOutID": 0,
				"ExtEventCardNo": "1874193998",
				"ExtEventCaseID": 0,
				"ExtEventCode": 197634,
				"ExtEventCustomerNumInfo": {
					"AccessChannel": 0,
					"EntryTimes": 0,
					"ExitTimes": 0,
					"TotalTimes": 0
				},
				"ExtEventDoorID": 1,
				"ExtEventIDCardPictureURL": "",
				"ExtEventIdentityCardInfo": {
					"Address": "",
					"Birth": "",
					"EndDate": "",
					"IdNum": "",
					"IssuingAuthority": "",
					"Name": "",
					"Nation": 0,
					"Sex": 0,
					"StartDate": "",
					"TermOfValidity": 0
				},
				"ExtEventInOut": 1,
				"ExtEventLocalControllerID": 0,
				"ExtEventMainDevID": 1,
				"ExtEventPersonNo": "0",
				"ExtEventPictureURL": "/pic?=d2=i689z260ds986-125mfep=t9i2i*d1=*ipd1=*isd8=*dbec775bf-84fbc12-484868-82i167*e172ed5",
				"ExtEventReaderID": 1,
				"ExtEventReaderKind": 0,
				"ExtEventReportChannel": 0,
				"ExtEventRoleID": 0,
				"ExtEventSubDevID": 0,
				"ExtEventSwipNum": 0,
				"ExtEventType": 0,
				"ExtEventVerifyID": 0,
				"ExtEventWhiteListNo": 0,
				"ExtReceiveTime": "1548828922319128",
				"Seq": 0,
				"svrIndexCode": "b1cded2b-2fbc-4255-aa9d-45162bfa23dd"
			},
			"eventId": "6B15F0C9947949D5BF271327C66BD658",
			"eventType": 197634,
			"eventTypeName": "acs.acs.eventType.wrongNoSuchCard",
			"happenTime": "2019-01-30T12:44:59.000+08:00",
			"srcIndex": "92ca80c786b843058e764f7fda863ae1",
			"srcName": "10.13.65.181_門1",
			"srcParentIndex": "de948e1856f74253b65848f4bef3fb03",
			"srcType": "door",
			"status": 0,
			"timeout": 0
		}],
		"sendTime": "2019-01-30T14:15:22.000+08:00"
	}
}

關(guān)于門禁事件上報報文格式參見一卡通應(yīng)用服務(wù)

2.3 實現(xiàn)過程

在這里插入圖片描述

在建立映射的過程中,只需要關(guān)注門禁設(shè)備的唯一標(biāo)識,ip,端口,門禁設(shè)備名稱。門禁點則只需要關(guān)注門禁點唯一標(biāo)識。

2.4 源碼實現(xiàn)

2.4.1 Controller

2.4.1.1 AcsDeviceController

AcsDeviceController用來獲取門禁設(shè)備的唯一標(biāo)識。

package com.example.platform.controller;

import com.example.platform.constants.Artemis;
import com.example.platform.utils.HttpClientSSLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * 獲取門禁設(shè)備信息的控制器
 *
 * @Owner:
 * @Time: 2019/3/1-15:45
 */
@RestController
@RequestMapping("/api/resource")
public class AcsDeviceController {
    private static final Logger logger = LoggerFactory.getLogger(AcsDeviceController.class);
    @Autowired
    private HttpClientSSLUtil httpClientSSLUtil;

    private static Map<String, String> acsDeviceAccessingUrl = new HashMap<>();
     static {
        acsDeviceAccessingUrl.put("allAcsDevice", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDevice/acsDeviceList");
        acsDeviceAccessingUrl.put("acsDeviceList", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDevice/advance/acsDeviceList");
        acsDeviceAccessingUrl.put("aAcsDeviceInfo", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDevice/indexCode/acsDeviceInfo");
    }
    public String getAllAcsDeviceUrl() {
         return acsDeviceAccessingUrl.get("allAcsDevice");
    }

    /**
     * @description: 獲取門禁設(shè)備列表
     * @url:
     * @author: Song Quanheng
     * @date: 2019/3/1-16:30
     * @return:
     */
    @GetMapping("/acsDevice/allAcsDevices")
    @ResponseBody
    public String getAllAcsDevices() {
         logger.info("Enter getAllAcsDevices");
        return httpClientSSLUtil.extractFullResourceList(getAllAcsDeviceUrl());
    }
}

門禁設(shè)備信息參見門禁設(shè)備信息

2.4.1.2 AcsDoorController

package com.example.platform.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.platform.constants.Artemis;
import com.example.platform.service.CommonReturn;
import com.example.platform.utils.HttpClientSSLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 獲取門禁點相關(guān)的信息,可支持按條件查詢,全量查詢,查詢單個門禁點的信息
 *
 * @Owner:
 * @Time: 2019/3/1-16:43
 */
@RestController
@RequestMapping("/api")
public class AcsDoorController {
    private static final Logger LOGGER = LoggerFactory.getLogger(AcsDoorController.class);

    public static final int ALWAYS_OPEN = 0;
    public static final int CLOSE = 1;
    public static final int OPEN = 2;
    public static final int ALWAYS_CLOSE = 3;


    public static final int MAX_DOOR_INDEX_NUM = 10;
    @Autowired
    private HttpClientSSLUtil httpClientSSLUtil;
    private static Map<String, String> acsDoorUrl = new HashMap<>();

    static {
        acsDoorUrl.put("allDoor", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDoor/acsDoorList");
        acsDoorUrl.put("doorList", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDoor/advance/acsDoorList");
        acsDoorUrl.put("aDoorInfo", Artemis.ARTEMIS_PATH+"/api/resource/v1/acsDoor/indexCode/acsDoorInfo");
        acsDoorUrl.put("doorControl", Artemis.ARTEMIS_PATH+"/api/acs/v1/door/doControl");
    }

    public String getAllDoorUrl() {
        return acsDoorUrl.get("allDoor");
    }

    public String getDoorControlUrl() {
        return acsDoorUrl.get("doorControl");
    }
    @GetMapping("/resource/acsDoor/allAcsDoors")
    public String getAllDoors() {
        LOGGER.info("Enter getAllDoors");
        return httpClientSSLUtil.extractFullResourceList(getAllDoorUrl());
    }

    @PostMapping(value = "/acs/door/doControl", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String controlDoor(@RequestBody JSONObject controlInfo) {
        if (hasValidControlInfo(controlInfo)) {
            LOGGER.debug("Enter controlDoor");
            return CommonReturn.httpReturnFailure("輸入的反控信息不正確");
        }
        httpClientSSLUtil.setHttpsUrl(getDoorControlUrl());
        return httpClientSSLUtil.doPostString(controlInfo.toJSONString());
    }

    private boolean hasValidControlInfo(JSONObject controlInfo) {
        if (!controlInfo.containsKey("doorIndexCodes") || !controlInfo.containsKey("controlType")) {
            return false;
        }
        JSONArray doorIndexCodes = controlInfo.getJSONArray("doorIndexCodes");
        if (doorIndexCodes.size()>MAX_DOOR_INDEX_NUM) {
            LOGGER.info("doorIndexCodes.size()>MAX_DOOR_INDEX_NUM");
            return false;
        }
        int controlType = controlInfo.getIntValue("controlType");
        Set<Integer> doorControlType = new HashSet<>();
        Collections.addAll(doorControlType, ALWAYS_OPEN, CLOSE, OPEN, ALWAYS_CLOSE);
        if (doorControlType.contains(controlType)) {
            LOGGER.debug("unsupported controlType: "+controlType);
            return false;
        }
        return true;
    }
}

2.4.2 Model

為了編程的方便,在代碼中為門禁點和門禁設(shè)備建模為類型,方便獲取某個特別屬性。比如說設(shè)備唯一標(biāo)識,門禁點唯一標(biāo)識。

2.4.2.1 AcsDevice

package com.example.platform.domain.dto;

import com.alibaba.fastjson.JSONObject;

/**
 * 門禁設(shè)備屬性說明
 *
 * @Owner: SongQuanHeng
 * @Time: 2019/3/28-15:56
 * @Version:
 * @Change: 新增,為門禁點到門禁設(shè)備的映射新增類型。
 */
public class AcsDevice {
    /**
     * 門禁設(shè)備唯一標(biāo)識
     */
    private String acsDevIndexCode;
    private String acsDevName;
    private String acsDevTypeDesc;
    private String acsDevTypeCode;
    private String acsDevTypeName;
    /**
     * 門禁設(shè)備Ip和端口
     */
    private String acsDevIp;
    private String acsDevPort;
    private String acsDevCode;
    private String regionIndexCode;
    private String treatyType;
    private String createTime;
    private String updateTme;


    public AcsDevice(JSONObject devInfo) {
        this.acsDevIndexCode = devInfo.getString("acsDevIndexCode");
        this.acsDevIp = devInfo.getString("acsDevIp");
        this.acsDevPort = devInfo.getString("acsDevPort");
    }

    public String getAcsDevIndexCode() {
        return acsDevIndexCode;
    }

    public String getAcsDevIp() {
        return acsDevIp;
    }

    public String getAcsDevPort() {
        return acsDevPort;
    }
}

2.4.2.2 AcsDoor

門禁點,在為了建立映射的過程中,只需要關(guān)注門禁點唯一標(biāo)識和門禁設(shè)備唯一標(biāo)識,這樣在建立映射關(guān)系時,可以根據(jù)門禁設(shè)備唯一標(biāo)識獲取該設(shè)備的基本信息。

package com.example.platform.domain.dto;

import com.alibaba.fastjson.JSONObject;

/**
 * 門禁點建模為類
 *
 * @Owner: SongQuanHeng
 * @Time: 2019/3/28-17:03
 * @Version:
 * @Change: 把門禁點建模為類
 */
public class AcsDoor {
    /**
     * 門禁點唯一標(biāo)識
     */
    private String doorIndexCode;
    /**
     * 所屬門禁設(shè)備唯一標(biāo)識
     */
    private String acsDevIndexCode;

    public AcsDoor(JSONObject doorInfo) {
        this.doorIndexCode = doorInfo.getString("doorIndexCode");
        this.acsDevIndexCode = doorInfo.getString("acsDevIndexCode");
    }

    public String getDoorIndexCode() {
        return doorIndexCode;
    }

    public void setDoorIndexCode(String doorIndexCode) {
        this.doorIndexCode = doorIndexCode;
    }

    public String getAcsDevIndexCode() {
        return acsDevIndexCode;
    }

    public void setAcsDevIndexCode(String acsDevIndexCode) {
        this.acsDevIndexCode = acsDevIndexCode;
    }
}

2.4.2.3 DoorMappingAcsDevice

DoorMappingAcsDevice類對應(yīng)的bean的靜態(tài)成員doorMapDevs負(fù)責(zé)保存映射關(guān)系。

package com.example.platform.constants;

import com.example.platform.domain.dto.AcsDevice;
import org.springframework.stereotype.Component;

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

/**
 * 該類負(fù)責(zé)門禁點映射成門禁設(shè)備
 *
 * @Owner: SongQuanHeng
 * @Time: 2019/3/28-16:18
 * @Version:
 * @Change:
 */
@Component
public class DoorMappingAcsDevice {

    private static Map<String, AcsDevice> doorMapDevs = new HashMap<>();
    public AcsDevice getAcsDevice(String doorIndexCode) {
        return doorMapDevs.get(doorIndexCode);
    }

    public void addAcsDevice(String doorIndexCode, AcsDevice device) {
        doorMapDevs.put(doorIndexCode, device);
    }

    public static Map<String, AcsDevice> getDoorMapDevs() {
        return Collections.unmodifiableMap(doorMapDevs);
    }
}

2.4.3 CommandLiner

該接口負(fù)責(zé)調(diào)用所有的Controller從服務(wù)器里獲取所有門禁點信息,所有門禁設(shè)備信息,進而構(gòu)建DoorMappingAvsDevice的運行時實例,即從門禁點唯一標(biāo)識到門禁設(shè)備信息的映射。

package com.example.platform.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.platform.constants.DoorMappingAcsDevice;
import com.example.platform.controller.AcsDeviceController;
import com.example.platform.controller.AcsDoorController;
import com.example.platform.domain.dto.AcsDevice;
import com.example.platform.domain.dto.AcsDoor;
import com.example.platform.utils.ReturnResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.stereotype.Component;

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

/**
 * 在所有Bean生成之后初始化資源
 * 通過在把該InitializeResource初始化資源類使用@Component注解,令該類成為容器管理的bean。
 * @Owner: SongQuanHeng
 * @Time: 2019/3/28-16:38
 * @Version:
 * @Change:
 */
@Component
public class InitializeResource implements CommandLineRunner {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //獲取所有門禁設(shè)備
    @Autowired
    private AcsDeviceController acsDeviceController;

    //獲取所有門禁點
    @Autowired
    private AcsDoorController acsDoorController;

    @Autowired
    private DoorMappingAcsDevice doorMappingAcsDevice;

    @Override
    public void run(String... args) throws Exception {
        logger.debug("Enter run");
        Map<String, AcsDevice> devMap = new HashMap<>();
        ReturnResult resDevs = new ReturnResult(acsDeviceController.getAllAcsDevices());
        if (!resDevs.isRequestSuccessful()) {
            logger.debug("acsDeviceController.getAllAcsDevices() fails");
            throw new Exception("acsDeviceController.getAllAcsDevices() fails");
        }
        JSONArray allDevs = resDevs.getResourceList();
        for (int i = 0; i < allDevs.size(); i++) {
            AcsDevice device = new AcsDevice(allDevs.getJSONObject(i));
            devMap.put(device.getAcsDevIndexCode(), device);
        }
        ReturnResult resDoors = new ReturnResult(acsDoorController.getAllDoors());
        if (!resDevs.isRequestSuccessful()) {
            logger.debug("acsDoorController.getAllDoors() fails");
            throw new Exception("acsDoorController.getAllDoors() fails");
        }
        JSONArray allDoors = resDoors.getResourceList();

        for (int i = 0; i < allDoors.size(); i++) {
            JSONObject doorInfo = allDoors.getJSONObject(i);
            AcsDoor door = new AcsDoor(allDoors.getJSONObject(i));

            String doorAcsDevIndexCode = door.getAcsDevIndexCode();
            if (!devMap.containsKey(doorAcsDevIndexCode)) {
                logger.debug("Impossible situation");
            } else {
                AcsDevice device = devMap.get(doorAcsDevIndexCode);
                doorMappingAcsDevice.addAcsDevice(door.getDoorIndexCode(), device);
            }
        }
        System.out.println("The Runner start to initialize");
    }
}

在此簡要的介紹依賴注入的概念。所謂依賴注入指的是容器負(fù)責(zé)創(chuàng)建對象和維護對象之間的關(guān)系,而不是通過對象本身負(fù)責(zé)自己的創(chuàng)建和解決自己的依賴。依賴注入的主要目的是為了解耦。體現(xiàn)了一種”組合”的理念。

Spring IoC容器(Application Context)負(fù)責(zé)創(chuàng)建Bean,并通過容器將功能類Bean注入到你需要的Bean中,Spring提供使用XML,注解,Java配置、groovy配置實現(xiàn)Bean的創(chuàng)建和注入。

通過上述InitializeResource可以看到,我們可以為一個Bean類注入Controller實例,并且調(diào)用Controller的REST接口以獲取數(shù)據(jù),然后把這些獲取的數(shù)據(jù)放入了DoorMappingAcsDevice的靜態(tài)變量中。

3 總結(jié)

文檔主要介紹了CommandLineRunner接口的應(yīng)用場景、并根據(jù)一個實例演示了使用CommandLineRunner來進行項目啟動之后的資源初始化,并通過在@Component注入@Controller領(lǐng)會Spring依賴注入的基本思想。

希望能夠通過此文檔幫助使用Spring Boot開發(fā)的程序員可以靈活的使用CommandLineRunner來完成項目自啟動,資源初始化類似的工作需求。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java使用阿里云接口進行身份證實名認(rèn)證的示例實現(xiàn)

    Java使用阿里云接口進行身份證實名認(rèn)證的示例實現(xiàn)

    這篇文章主要介紹了使用阿里云接口進行身份證實名認(rèn)證的示例實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 一個簡單的Java音樂播放器

    一個簡單的Java音樂播放器

    這篇文章主要為大家分享一個簡單的Java音樂播放器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解

    Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解

    這篇文章主要為大家介紹了Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • MyBatis結(jié)果映射(ResultMap)的使用

    MyBatis結(jié)果映射(ResultMap)的使用

    在MyBatis中,結(jié)果映射是實現(xiàn)數(shù)據(jù)庫結(jié)果集到Java對象映射的核心,它不僅支持簡單的字段映射,還能處理字段名不一致、嵌套對象和集合映射等復(fù)雜場景,通過ResultMap,開發(fā)者可以靈活定義映射關(guān)系,以適應(yīng)各種需求,感興趣的可以了解一下
    2024-09-09
  • SpringBoot使用JTA實現(xiàn)對多數(shù)據(jù)源的事務(wù)管理

    SpringBoot使用JTA實現(xiàn)對多數(shù)據(jù)源的事務(wù)管理

    了解事務(wù)的都知道,在我們?nèi)粘i_發(fā)中單單靠事務(wù)管理就可以解決絕大多數(shù)問題了,但是為啥還要提出JTA這個玩意呢,到底JTA是什么呢?他又是具體來解決啥問題的呢?本文小編就給大家介紹一下如何在Spring Boot中使用JTA實現(xiàn)對多數(shù)據(jù)源的事務(wù)管理
    2023-11-11
  • Springboot?內(nèi)部服務(wù)調(diào)用方式

    Springboot?內(nèi)部服務(wù)調(diào)用方式

    這篇文章主要介紹了Springboot?內(nèi)部服務(wù)調(diào)用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java實現(xiàn)簡單登錄界面的實戰(zhàn)過程

    java實現(xiàn)簡單登錄界面的實戰(zhàn)過程

    學(xué)習(xí)JAVA的過程當(dāng)中,登陸界面是多數(shù)人第一個實現(xiàn)的小程序,下面這篇文章主要給大家介紹了關(guān)于利用java實現(xiàn)簡單登錄界面的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-05-05
  • Springboot Redis設(shè)置key前綴的方法步驟

    Springboot Redis設(shè)置key前綴的方法步驟

    這篇文章主要介紹了Springboot Redis設(shè)置key前綴的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Pattern.compile函數(shù)提取字符串中指定的字符(推薦)

    Pattern.compile函數(shù)提取字符串中指定的字符(推薦)

    這篇文章主要介紹了Pattern.compile函數(shù)提取字符串中指定的字符,使用的是Java中的Pattern.compile函數(shù)來實現(xiàn)對指定字符串的截取,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • Spring線程池ThreadPoolTaskExecutor的用法及說明

    Spring線程池ThreadPoolTaskExecutor的用法及說明

    這篇文章主要介紹了Spring線程池ThreadPoolTaskExecutor的用法及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評論