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

使用Spring?Boot?2.x構(gòu)建Web服務(wù)的詳細(xì)代碼

 更新時間:2022年03月18日 11:08:25   作者:盧鑫旺  
這篇文章主要介紹了使用Spring?Boot?2.x構(gòu)建Web服務(wù)的詳細(xì)代碼,主要基于JWT的身份認(rèn)證,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

架構(gòu):

  • MVC架構(gòu)
  • 基于JWT的身份認(rèn)證
  • Spring Data (JPA)
  • 應(yīng)用用戶密碼加密
  • 數(shù)據(jù)庫密碼加密
  • SQL Server
  • Slf4j
  • 基于Swagger的API文檔

庫:

  • 應(yīng)用源代碼
  • 數(shù)據(jù)庫的SQL腳本以及關(guān)鍵數(shù)據(jù)
  • 包含數(shù)據(jù)庫配置信息的DB.txt文件
  • 用于測試Web服務(wù)的Postman JSON腳本

運(yùn)行應(yīng)用的步驟

  • 安裝JDK11或最新版本
  • 克隆項目庫到本地
  • Git地址:https://github.com/VishnuViswam/sample-web-service.git
  • 安裝SQL server 2012
  • 創(chuàng)建應(yīng)用數(shù)據(jù)庫和用戶
  • 插入數(shù)據(jù)庫密鑰數(shù)據(jù)
  • 將數(shù)據(jù)庫密碼的解碼密鑰添加到系統(tǒng)變量,它位于DB.txt文件中
  • 有時可能需要重新啟動窗口以獲取更新后的系統(tǒng)變量
  • 運(yùn)行項目源代碼
  • 導(dǎo)入預(yù)先提供的postman JSON腳本到postman客戶端,調(diào)用Web服務(wù)

關(guān)于項目配置

Web服務(wù)聲明

應(yīng)用程序的每個Web服務(wù)都將在controller層中聲明。

示例

@RequestMapping("/api/v1/user")
@RestController
@Validated
public class UserController {

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

    @Autowired
   private GeneralServices generalServices;

   @Autowired
   private UserService userService;

   /**
     * Web service to create new user
     *
     * @param httpServletRequest
    * @param user
     * @return
    */
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Object> createUser(HttpServletRequest httpServletRequest,
                                             @Valid @RequestBody UserCreateModel user) {
       logger.debug("<--- Service to save new user request : received --->");
       ApiSuccessResponse apiResponse = userService.createUser(user, generalServices.getApiRequestedUserId(httpServletRequest));
        logger.debug("<--- Service to save new user response : given --->");
       return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);

    }

}
  • @RequestMapping("/api/v1/user")注解用來聲明Web服務(wù)的類別
  • @RestController注解配置該類來接收Restful的 Web服務(wù)調(diào)用
  • @PostMapping()注解決定了HTTP請求類型
  • consume和consume標(biāo)記來確定HTTP請求和響應(yīng)的內(nèi)容類型

通過controller層,API請求將被帶到服務(wù)層。所有業(yè)務(wù)邏輯都將在這里處理,然后它將使用JPA與數(shù)據(jù)庫通信。

通用錯誤處理

每當(dāng)異常發(fā)生時,它將從相應(yīng)的類拋出,并在CommonExceptionHandlingController中處理。我們必須分別處理每種異常類型。這個功能是在ControllerAdvice注解的幫助下執(zhí)行的。

示例

@ControllerAdvice
public?class?CommonExceptionHandlingController?extends?ResponseEntityExceptionHandler?{

????private?static?final?Logger?logger?=?
????????LoggerFactory.getLogger(CommonExceptionHandlingController.class);
???@Override
????protected?ResponseEntity<Object>?handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException?httpRequestMethodNotSupportedException,
?????????????????????????????????????????????????????????????????????????HttpHeaders?headers,?HttpStatus?status,?WebRequest?request)?{
???????return?ResponseEntity.status(HttpStatus.NOT_FOUND).body(new?ApiErrorResponse(Constants.WRONG_HTTP_METHOD,
????????????????Constants.WRONG_HTTP_METHOD_ERROR_MESSAGE,?Calendar.getInstance().getTimeInMillis()));
???}
???protected?ResponseEntity<Object>?handleMethodArgumentNotValid(MethodArgumentNotValidException?methodArgumentNotValidException,
?????????????????????????????????????????????????????????????????HttpHeaders?headers,?HttpStatus?status,?WebRequest?request)?{
???????return?ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new?ApiErrorResponse(Constants.MANDATORY_FIELDS_ARE_NOT_PRESENT_CODE,
???????????????Constants.MANDATORY_FIELDS_ARE_NOT_PRESENT_ERROR_MESSAGE,?Calendar.getInstance().getTimeInMillis()));

Spring Data(JPA)配置

  • 應(yīng)用程序與數(shù)據(jù)庫的所有交互都將由JPA處理
  • JPA將為應(yīng)用程序中的所有邏輯對象提供一個Entity類和一個相應(yīng)的Repository接口

Entity類

@Entity
@Table(name?=?"tbl_users")
public?class?Users?implements?Serializable?{
???private?static?final?long?serialVersionUID?=?1L;

??@Id
???@GeneratedValue(strategy?=?GenerationType.IDENTITY)
???@Column(name?=?"id",?columnDefinition?=?"bigint")
????private?Long?id;

??@OneToOne(fetch?=?FetchType.EAGER)
??@JoinColumn(name?=?"user_account_id",?columnDefinition?=?"bigint",?nullable?=?false)
???private?UserAccounts?userAccount;

Repository接口

public?interface?UserRepository?extends?JpaRepository<Users,?Long>?{

???/**
?????*?To?find?user?object?using?username
?????*
????*?@param?username
????*?@return
?????*/
??Users?findByUserAccountUsername(String?username);
  • 其他的JPA配置將會在application.properties文件中完成

在application.properties中的JPA數(shù)據(jù)庫配置

spring.jpa.show-sql=false
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto?=?update

spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.properties.hibernate.use_sql=true
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider

數(shù)據(jù)庫配置

  • 數(shù)據(jù)庫名稱寫在application.properties文件中
  • 其他信息(比如URL連接地址和賬號密碼)將寫到另外兩個不同屬性文件中

application-dev.properties

此處寫開發(fā)環(huán)境的配置信息

application-pro.properties

此處寫生產(chǎn)環(huán)境的配置信息

spring.profiles.active=dev
  • 上述提到的屬性配置寫到application.properties文件中
  • 它將決定系統(tǒng)使用哪個子配置文件(開發(fā)環(huán)境還是生產(chǎn)環(huán)境)

application.properties

#DB?config
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

application-dev.properties

#DB?config
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=sample_webservice_db_dev
spring.datasource.username=dbuser
spring.datasource.password=ENC(tZTfehMYyz4EO0F0uY8fZItE7K35RtkA)
#spring.datasource.username=dbuser
#spring.datasource.password=dbuserpassword

application-pro.properties

#DB?config
spring.datasource.url=jdbc:sqlserver://192.168.1.119:1433;databaseName=sample_webservice_db
spring.datasource.username=proUser
spring.datasource.password=ENC(proUserPswd)

數(shù)據(jù)庫密碼加密

  • 應(yīng)用程序數(shù)據(jù)庫密碼會使用加密密鑰通過__Jasypt __ 庫加密。
  • 加密密鑰需要添加到系統(tǒng)環(huán)境變量中的JASYPT_ENCRYPTOR_PASSWORD變量中。
  • 必須在屬性文件中聲明加密后的數(shù)據(jù)庫密碼。如此,系統(tǒng)就會了解密碼需要解密,而解密則需要使用添加在系統(tǒng)變量中的密鑰來進(jìn)行。
spring.datasource.password=ENC(tZTfehMYyz4EO0F0uY8fZItE7K35RtkA)
  • 對于__Jasypt __加密,我們在屬性文件中使用默認(rèn)的加密配置,如下所示:
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator
  • 我們也可以在應(yīng)用的main方法中使用@EnableEncryptableProperties注解,規(guī)定數(shù)據(jù)庫密碼的加密配置

SampleWebservice.java

@SpringBootApplication
@EnableEncryptableProperties
public?class?SampleWebservice?extends?SpringBootServletInitializer?{
--------
--------

JWT身份驗證配置

  • 使用Spring Security實(shí)現(xiàn)基于JSON Web令牌的身份驗證
  • 當(dāng)用戶登錄成功時,我們會創(chuàng)建兩個token(accessToken 和 refreshToken)并把他們返回給客戶端
  • accessToken由私鑰,過期時間(1小時),用戶ID和角色名生成
  • refreshToken由私鑰,過期時間(24小時),用戶ID和角色名生成
  • 登陸成功后,每個API請求都需要在請求頭Header中的Authorization鍵中添加accessToken
  • 在accessToken開頭添加"bearer"字符串
  • 即為”bearer accessToken”
  •  accessToken將會監(jiān)控每一個Web服務(wù)請求
  • 如果accessToken過期,系統(tǒng)會以HTTP 401狀態(tài)碼回復(fù)請求
  • 此時客戶端需要使用refreshToken重新獲取accessToken
  • 然后我們會檢查refreshToken的有效性,如果沒有過期則會生成一個新的accessToken和refreshToken
  • 客戶端會繼續(xù)使用這些新令牌
  • 如果refreshToken也過期了,就需要用戶使用賬號密碼重新登陸了

創(chuàng)建令牌的過程

UnAuthorisedAccessServiceImpl.java

@Override
???public?ApiSuccessResponse?userLoginService(String?username,?String?password)?{
??????Tokens?tokens?=?null;
???????Users?user?=?userService.findByUsername(username);
???????if?(user?!=?null)?{
???????????if?(passwordEncryptingService.matches(password,
???????????????????user.getUserAccount().getPassword()))?{
???????????????if?(user.getUserAccount().getStatus()?==?Constants.ACTIVE_STATUS)?{
???????????????????String?roleName?=?user.getUserAccount().getUserRole().getRoleName();
???????????????????//?Creating?new?tokens
??????????????????try?{
???????????????????????tokens?=?createTokens(user.getUserAccount().getId().toString(),?roleName);
??????????????????}?catch?(Exception?exception)?{
????????????????????????logger.error("Token?creation?failed?:?",?exception);
??????????????????????throw?new?UnknownException();
???????????????????}

???????????????????//?Validating?tokens
??????????????????if?(validationService.validateTokens(tokens))?{
???????????????????????tokens.setUserId(user.getUserAccount().getId());
?????????????????????return?new?ApiSuccessResponse(tokens);
??????????????????}?else?{
???????????????????????throw?new?UnknownException();
??????????????????}
??????????????}?else?{
?????????????????return?new?ApiSuccessResponse(new?ApiResponseWithCode(Constants.USER_ACCOUNT_IS_INACTIVE_ERROR_CODE,
???????????????????????????Constants.USER_ACCOUNT_IS_INACTIVE_ERROR_MESSAGE));
?????????????}
??????????}?else?{
??????????????return?new?ApiSuccessResponse(new?ApiResponseWithCode(Constants.USERNAME_OR_PASSWORD_IS_INCORRECT_ERROR_CODE,
???????????????????????Constants.USERNAME_OR_PASSWORD_IS_INCORRECT_ERROR_MESSAGE));
???????????}
??????}?else?{
???????????return?new?ApiSuccessResponse(new?ApiResponseWithCode(Constants.USERNAME_OR_PASSWORD_IS_INCORRECT_ERROR_CODE,
??????????????????Constants.USERNAME_OR_PASSWORD_IS_INCORRECT_ERROR_MESSAGE));
???????}
????}
????@Override
???public?ApiSuccessResponse?createNewAccessTokenUsingRefreshToken(String?refreshToken)?{
????????UserAccounts?userAccount?=?null;
???????AppConfigSettings?configSettings?=?appConfigSettingsService.findByConfigKeyAndStatus(Constants.JWT_SECRET_KEY,
???????????????Constants.ACTIVE_STATUS);
??????//?Validate?Refresh?token
???????userAccount?=?jwtTokenHandler.validate(configSettings.getConfigValue(),?refreshToken);
???????if?(userAccount?!=?null)?{
????????????//?Creating?new?tokens?if?provided?refresh?token?is?valid
???????????try?{
???????????????tokens?=?createTokens(userAccount.getId().toString(),?userAccount.getRole());
???????????}?catch?(Exception?exception)?{
??????????????logger.error("Token?creation?failed?:?",?exception);
???????????????throw?new?UnknownException();
??????????if?(validationService.validateTokens(tokens))?{
???????????????tokens.setUserId(userAccount.getId());
??????????????return?new?ApiSuccessResponse(tokens);
???????????}?else?{
??????????}
???????}?else?{
???????????return?new?ApiSuccessResponse(new?ApiResponseWithCode(Constants.REFRESH_TOKEN_EXPIRED_ERROR_CODE,
??????????????????Constants.REFRESH_TOKEN_EXPIRED_ERROR_MESSAGE));
??????}
???}
  • 上述代碼中的userLoginService方法會檢查用戶憑據(jù),如果有效則頒發(fā)令牌。
  • CreateNewAccessTokenUsingRefreshToken方法會在refreshToken驗證成功后,生成新的accessToken和refreshToken。

過濾和驗證令牌的過程

WebConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled?=?true)
public?class?WebConfig?extends?WebSecurityConfigurerAdapter?{

???@Autowired
???private?JwtAuthenticationProvider?authenticationProvider;
????@Autowired
???private?JwtAuthenticationEntryPoint?entryPoint;
????@Bean
????public?AuthenticationManager?authenticationManager()?{
????????return?new?ProviderManager(Collections.singletonList(authenticationProvider));
???}
??public?JwtAuthenticationTokenFilter?authenticationTokenFilter()?{
??????JwtAuthenticationTokenFilter?filter?=?new?JwtAuthenticationTokenFilter();
????????filter.setAuthenticationManager(authenticationManager());
??????filter.setAuthenticationSuccessHandler(new?JwtSuccessHandler());
????????return?filter;
????@Override
????protected?void?configure(HttpSecurity?http)?throws?Exception?{
???????http.csrf().disable()
???????????????.exceptionHandling().authenticationEntryPoint(entryPoint).and().sessionManagement()
????????????????.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
?????????????.addFilterBefore(new?WebSecurityCorsFilter(),?ChannelProcessingFilter.class)
???????????????.addFilterBefore(authenticationTokenFilter(),?UsernamePasswordAuthenticationFilter.class)
????????????????.headers().cacheControl();
????}
}
  • 這個配置將使用@EnableWebSecurity和@EnableGlobalMethodSecurity(prePostEnabled = true)兩個注解來啟用spring security模塊
  • 這里,我們將把JWT過濾器注入到系統(tǒng)的HTTP請求中

JwtAuthenticationTokenFilter.java

public?class?JwtAuthenticationTokenFilter?extends?AbstractAuthenticationProcessingFilter?{

???private?final?Logger?logger?=?LoggerFactory.getLogger(this.getClass());
????@Autowired
???private?GeneralServices?generalServices;
??public?JwtAuthenticationTokenFilter()?{
???????super("/api/**");
???}
????@Override
????public?Authentication?attemptAuthentication(HttpServletRequest?httpServletRequest,
????????????????????????????????????????????????HttpServletResponse?httpServletResponse)?throws?AuthenticationException,?IOException,?ServletException?{
?????????????????????????????????????????????????-------
?????????????????????????????????????????????????--------
  • 在如上的類中,JwtAuthenticationTokenFilter()的方法將過濾所有URL中含有“api”命名關(guān)鍵字的Web服務(wù)請求
  • 所有經(jīng)過過濾的Web服務(wù)請求將到達(dá)attemptAuthentication方法
  • 我們可以在這個方法里處理所有的業(yè)務(wù)邏輯

應(yīng)用用戶密碼加密

  • 該應(yīng)用中所有的用戶密碼都將會使用BCrypt加密

PasswordEncryptingService.java

public?class?PasswordEncryptingService?{

????public?String?encode(CharSequence?rawPassword)?{
????????return?BCrypt.hashpw(rawPassword.toString(),?BCrypt.gensalt(6));
????}

????public?boolean?matches(CharSequence?rawPassword,?String?encodedPassword)?{
????????return?BCrypt.checkpw(rawPassword.toString(),?encodedPassword);
????}
  • 這里,encode方法用來加密密碼
  • matches方法用來交叉檢查提供的密碼和用戶的實(shí)際密碼

使用Slf4j配置日志

  • 在一個叫l(wèi)ogback-spring.xml的文件中配置日志
  • 為了記錄每個類的日志,我們需要在相應(yīng)的類中注入Slf4j

示例

UserServiceImpl.java

@Service("UserService")
@Scope("prototype")
public?class?UserServiceImpl?implements?UserService?{
????private?static?final?Logger?logger?=?LoggerFactory.getLogger(UserServiceImpl.class);
  • 上面的代碼片段顯示了我們?nèi)绾螌㈩愖⑷氲絣ogger
  • 以下是記錄日志的一些基本方法

logger.error("Error");

logger.info("Info");

logger.warn("Warn");

基于Swagger的API文檔

  • API文檔在Web服務(wù)應(yīng)用程序中扮演著重要的角色
  • 之前,我們使用靜態(tài)Excel文檔創(chuàng)建API文檔
  • 這個庫將幫助我們在應(yīng)用程序中使用注釋創(chuàng)建API文檔

Pom.xml

??<dependency>
????????????<groupId>io.springfox</groupId>
????????????<artifactId>springfox-boot-starter</artifactId>
????????????<version>${springfox.swagger.version}</version>
????????</dependency>

????????<dependency>
????????????<groupId>io.springfox</groupId>
????????????<artifactId>springfox-swagger-ui</artifactId>
????????????<version>${springfox.swagger.version}</version>
????????</dependency>
  • 為了集成Swagger,上述這些是我們要在pom文件中添加的庫
  • 我們需要在應(yīng)用程序中做一些配置來啟用API文檔

SwaggerAPIDocConfig.java

@Configuration
@EnableSwagger2
public?class?SwaggerAPIDocConfig?{

????public?static?final?Contact?DEFAULT_CONTACT?=?new?Contact("Demo",?"http://www.demo.ae/",
????????????"info@demo.ae");
????public?static?final?ApiInfo?DEFAUL_API_INFO?=?new?ApiInfo("Sample?Application",
????????????"Sample?Application?description.",
????????????"1.0.0",
????????????"http://www.sampleapplication.ae/",
????????????DEFAULT_CONTACT,?"Open?licence",
????????????"http://www.sampleapplication.ae/#license",
????????????new?ArrayList<VendorExtension>());
????private?static?final?Set<String>?DEFAULT_PRODICERS_AND_CONSUMERS?=
????????????new?HashSet<>(Arrays.asList("application/json",?"application/xml"));
????@Bean
????public?Docket?api()?{
????????return?new?Docket(DocumentationType.SWAGGER_2)
????????????????.apiInfo(DEFAUL_API_INFO)
????????????????.produces(DEFAULT_PRODICERS_AND_CONSUMERS)
????????????????.consumes(DEFAULT_PRODICERS_AND_CONSUMERS)
????????????????.select()
????????????????.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
????????????????.paths(PathSelectors.any())
????????????????.build();
????}
}
  • 正如在上邊的類中看到的,我們需要添加關(guān)于項目的基本信息
  • 我們需要告訴Swagger從哪個類創(chuàng)建API文檔,這是在.apis(RequestHandlerSelectors.withClassAnnotation,(RestController.class))命名行下配置的
  • 我們可以通過http://localhost:8080/sampleWebService/apidoc來訪問Swagger的API文檔

Postman腳本

  • 我們可以在代碼庫中找到2個Postman JSON腳本,然后將它們導(dǎo)入到Postman客戶端
  • 首先執(zhí)行登陸的Web服務(wù)請求,然后執(zhí)行其余web服務(wù)請求

到此這篇關(guān)于使用Spring Boot 2.x構(gòu)建Web服務(wù)的詳細(xì)代碼的文章就介紹到這了,更多相關(guān)Spring Boot 2.x構(gòu)建Web服務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot整合Spring Cache及Redis過程解析

    Spring Boot整合Spring Cache及Redis過程解析

    這篇文章主要介紹了Spring Boot整合Spring Cache及Redis過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • logback標(biāo)記日志過濾器MarkerFilter源碼解讀

    logback標(biāo)記日志過濾器MarkerFilter源碼解讀

    這篇文章主要為大家介紹了logback標(biāo)記日志過濾器MarkerFilter源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Springboot集成規(guī)則引擎Drools方式

    Springboot集成規(guī)則引擎Drools方式

    這篇文章主要介紹了Springboot集成規(guī)則引擎Drools方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java17中record替代Lombok部分功能使用場景探究

    Java17中record替代Lombok部分功能使用場景探究

    這篇文章主要介紹了使用Java17中的record替代Lombok的部分功能,本文來為大家小小的總結(jié)下,我們可以在哪些地方,利用record來替換Lombok
    2024-01-01
  • Java 十大排序算法之希爾排序刨析

    Java 十大排序算法之希爾排序刨析

    希爾排序是希爾(Donald Shell)于1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經(jīng)過改進(jìn)之后的一個更高效的版本,也稱為縮小增量排序,同時該算法是沖破O(n2)的第一批算法之一。本文會以圖解的方式詳細(xì)介紹希爾排序的基本思想及其代碼實(shí)現(xiàn)
    2021-11-11
  • Java多線程并發(fā)編程 Volatile關(guān)鍵字

    Java多線程并發(fā)編程 Volatile關(guān)鍵字

    volatile 關(guān)鍵字是一個神秘的關(guān)鍵字,也許在 J2EE 上的 JAVA 程序員會了解多一點(diǎn),但在 Android 上的 JAVA 程序員大多不了解這個關(guān)鍵字。只要稍了解不當(dāng)就好容易導(dǎo)致一些并發(fā)上的錯誤發(fā)生,例如好多人把 volatile 理解成變量的鎖
    2017-05-05
  • 深入理解java中的null“類型”

    深入理解java中的null“類型”

    這篇文章主要介紹了深入理解java中的null“類型”,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • java中邏輯控制舉例具體講解

    java中邏輯控制舉例具體講解

    Java程序邏輯控制通俗說就是對代碼執(zhí)行順序的控制,這篇文章主要給大家介紹了關(guān)于java中邏輯控制的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Java中常見死鎖與活鎖的實(shí)例詳解

    Java中常見死鎖與活鎖的實(shí)例詳解

    這篇文章主要介紹了Java中常見死鎖與活鎖的實(shí)例詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Java 字符串連接的性能問題分析

    Java 字符串連接的性能問題分析

    這篇文章主要介紹了Java 字符串連接的性能問題分析的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評論