> Java > java지도 시간 > Java 생태계에서 누락된 스크립팅 도구인 Jbang

Java 생태계에서 누락된 스크립팅 도구인 Jbang

Patricia Arquette
풀어 주다: 2025-01-05 04:01:39
원래의
193명이 탐색했습니다.

Java 생태계에는 이미 Maven과 Gradle이라는 두 가지 강력한 프로젝트 관리 도구가 있지만 간단하고 강력한 스크립팅 도구가 부족했습니다.
JBang이 등장하는 곳입니다.
미니멀하지만 강력한 Java, Kotlin 및 Groovy 파일 실행기입니다.
실제로 이를 사용하면 스크립트를 실행하는 것처럼 쉽게 코드를 실행할 수 있습니다.
또한 종속성 관리, 템플릿, App Store 등 다양한 기능을 제공합니다.
이번 포스팅에서는 Jbang과 그 기능을 살펴보겠습니다.

설정

jbang 명령줄은 여기에 잘 설명되어 있는 다양한 방법을 사용하여 Windows, Linux 및 macOS에 설치할 수 있습니다.
jbang --version을 실행하여 설치를 확인할 수 있습니다.

또한 우리가 가장 좋아하는 IDE에 대해 함께 제공되는 IDE 확장을 설치하는 것이 좋습니다.
지원되는 IDE 확장은 여기에 나열되어 있습니다.

JBang은 JDK에서 JRE에 의존하지 않지만 Java를 사용하는 스크립트를 실행하려면 JDK가 필요합니다.
JDK 23을 설치하는 jbang jdk install 23을 실행하여 Jbang과 함께 설치할 수 있습니다.

이제 첫 번째 스크립트를 작성할 준비가 되었습니다.

첫 번째 스크립트

"Hello, World!"를 인쇄하는 간단한 스크립트를 만들어 보겠습니다. 콘솔로.

> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이렇게 하면 jbang helloworld.java에서 실행할 수 있는 helloworld.java라는 파일이 생성됩니다.

> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

파일을 열면 기본 메소드와 특정 첫 번째 줄이 포함된 일반 Java 파일임을 알 수 있습니다.

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

앞으로 살펴보겠지만 Jbang 스크립트는 shebang, 선택적 속성, 스크립트 자체의 세 부분으로 구성됩니다.
다음 섹션에서는 두 번째 부분의 일부 속성을 사용하겠지만 첫 번째 부분에 집중하겠습니다.

이 부분 ///usr/bin/env jbang "$0" "$@" ; $를 종료하시겠습니까? 스크립트를 실행하기 위해 Jbang을 사용하도록 시스템에 지시합니다.
유닉스 생태계에서는 셰뱅(shebang)이라고 부르며, 스크립트에 대한 인터프리터를 지정하는 데 사용됩니다.
chmod x helloworld.java를 실행하여 스크립트를 실행 가능하게 만든 다음 ./helloworld.java를 실행하여 Unix 시스템(macOS, Linux)에서 이를 설명할 수 있습니다.

/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

이제 Java 파일을 사용하는 것처럼 스크립트를 개발할 수 있습니다.
게시할 준비가 되면 다음과 같이 다양한 형식으로 내보낼 수 있습니다.

  • jar 파일: jbang import Portable helloworld.java. 스크립트가 종속성을 사용하는 경우 다음 명령을 사용하는 것이 더 좋습니다.
  • A fatjar: 모든 종속성을 포함합니다: jbang import fatjar helloworld.java. 이 방법을 사용하려면 대상 시스템에 JDK/JRE를 설치해야 합니다. 그게 싫으시다면 다음 명령어를 더 추천드려요.
  • JDK를 포함하는 jlink 바이너리: jbang 내보내기 jlink helloworld.java. 실행할 바이너리는 Unix의 helloworld-jlink/bin/helloworld 또는 Windows의 helloworld-jlink/bin/helloworld.bat입니다.
  • 네이티브 이미지: jbang 내보내기 네이티브 helloworld.java. 이를 위해서는 GraalVM 설치가 필요합니다.

다음을 사용하여 스크립트를 mavenrepo로 내보낼 수도 있습니다. jbang import mavenrepo helloworld.java

JDK 관리

이전 장에서 본 것처럼 Jbang은 컴퓨터에 JDK를 설치할 수 있습니다.
jbang jdk list를 사용하여 설치된 JDK를 나열하고, jbang jdk list --available --show-details를 사용하여 설치할 수 있는 JDK를 나열하고, jbang jdk install [version]을 사용하여 새 JDK를 설치할 수 있습니다. Jbang은 SDKMAN을 사용하여 지원되는 시스템에서 JDK를 관리하는 것도 지원합니다.

또한 스크립트에서 JDK 버전을 지정할 수도 있습니다.
이는 스크립트 속성에 다음 행을 추가하여 수행됩니다. 정확한 버전을 원하는 경우 //JAVA [버전], 최소한 특정 버전을 원하는 경우 //JAVA [버전]
이 경우 Jbang은 필요한 JDK 버전을 자동으로 설치하고 시스템의 기본 JDK를 변경하지 않고 해당 스크립트에만 사용합니다.

예를 들어 다음 스크립트는 Java 25 및 일부 미리보기 기능을 사용합니다.

> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

"Main" 클래스가 없는 스크립트

스크립트는 가벼운 편이므로 클래스나 메인 메소드 없이 작성하는 것이 바람직합니다.
다행스럽게도 Java에는 암시적 선언 클래스 및 인스턴스 기본 메소드라는 기능이 있습니다(Java 23에서는 아직 미리 보기 상태입니다).
이 기능을 사용하면 클래스 및 정적 메인 메소드 없이 Java 프로그램 및 Jbang 스크립트를 작성할 수 있습니다.

다음 스크립트는 문제없이 컴파일 및 실행됩니다.

> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

스크립트에 다음 속성을 추가하면 가능합니다.

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

첫 번째 줄 //JAVA 23 은 Jbang이 Java 23 이상을 사용하도록 지시합니다.
두 번째 및 세 번째 줄인 //COMPILE_OPTIONS --enable-preview -source 23 및 //RUNTIME_OPTIONS --enable-preview는 각각 컴파일 및 런타임에 대한 미리 보기 기능을 활성화합니다.

기능이 안정화되면 3줄을 제거해도 스크립트는 계속 작동합니다. 깔끔해요!

종속성

JBang은 각 종속성에 대해 //DEPS atrefact-id:atrefact-name:version 라인을 추가하여 Gradle 스타일 종속성 형태로 스크립트에 종속성을 추가하는 것을 지원합니다.
예를 들어, jfiglet 라이브러리를 사용하려면 스크립트에 다음 줄을 추가하면 됩니다: //DEPS com.github.lalyos:jfiglet:0.0.8.

> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

카탈로그

JBang의 카탈로그를 사용하면 스크립트와 템플릿을 효율적으로 구성하고 공유할 수 있습니다.
이 기능은 일반적인 작업이나 워크플로를 위한 스크립트 모음을 공유하려는 팀이나 커뮤니티에 특히 유용합니다.
소스코드를 제공하지 않고 스타터 코드를 배포하거나 연습 결과를 보여주고 싶은 교사에게도 유용합니다.

카탈로그는 별칭과 템플릿이라는 두 가지 항목 그룹을 포함하는 jbang-catalog.json이라는 JSON 파일입니다.
별칭을 사용하면 간단한 명령을 사용하여 카탈로그에서 스크립트를 실행할 수 있으며 템플릿은 새 스크립트의 시작점을 제공합니다.
카탈로그는 원격 또는 로컬일 수 있으며 필요에 따라 많은 로컬 또는 원격 저장소를 추가하고 사용할 수 있습니다.
Jbang이 설정 중에 일부 별칭과 템플릿이 포함된 로컬 카탈로그를 즉시 생성한다는 점이 흥미롭습니다.

JBang은 다음 순서로 이러한 디렉토리에서 로컬 카탈로그를 찾습니다(출처 JBang 문서):

  1. 현재 디렉터리, ./jbang-catalog.json
  2. ./.jbang/jbang-catalog.json에서
  3. 상위 디렉터리 ../jbang-catalog.json
  4. 부모의 .jbang 디렉터리에서 ../.jbang/jbang-catalog.json
  5. 그리고 3단계와 4단계를 파일 시스템의 루트까지 위쪽으로 재귀적으로 반복합니다
  6. 마지막 단계로 $HOME/.jbang/jbang-catalog.json을 살펴보겠습니다.

JBang은 GitHub, GitLab, Bitbucket 등과 같은 많은 오픈 소스 저장소에서 원격으로 카탈로그를 찾습니다.
이번 포스팅에서는 GitHub를 예로 들어보겠습니다.
원격 카탈로그를 생성하려면 저장소의 루트 폴더에 jbang-catalog.json을 추가해야 합니다.
그런 다음 카탈로그는 account/repository_name으로 참조됩니다.
저장소 이름이 jbang-catalog이면 계정별로 참조할 수 있습니다.
예를 들어 내 GitHub 계정의 이름이 yostane이고 jbang-catalog.json이라는 파일이 포함된 카탈로그가 포함된 cours-java라는 저장소가 있는 경우 yostane/cours-java로 해당 카탈로그를 참조할 수 있습니다. 또한 jbang-catalog라는 저장소에 jbang-catalog.json이 있으면 yostane/jbang-catalog 또는 간단히 yostane으로 참조할 수 있습니다.

> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음 장에서는 카탈로그의 별칭과 템플릿을 사용하는 방법을 보여줍니다.

별칭

JBang의 별칭을 사용하면 카탈로그에서 스크립트를 실행할 수 있습니다.
전체 구문은 각각 원격 및 로컬 별칭에 대한 jbang alias@account/repository [args] 및 jbang alias [args]입니다.

별칭은 다음 형식을 사용하여 카탈로그 파일의 별칭 섹션에서 정의할 수 있습니다.

> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

DevoxxMA 2024 세션에서 사용한 카탈로그입니다.

> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음 명령을 사용하여 이러한 별칭을 실행할 수 있습니다.

  • jbang palcli@yostane/cours-java 마담
  • jbang palqrest@yostane/cours-java
  • jbang hellojfx@yostane/cours-java

JBang GitHub 공식 계정은 다양한 별칭과 템플릿이 포함된 카탈로그를 제공합니다.
그 중 일부를 실행해 보겠습니다.

  • jbang httpd@jbangdev는 로컬 웹서버를 실행합니다.
  • jbang gavsearch@jbangdev [arg] search.maven.org에서 [arg]를 검색하세요.

템플릿

새 스크립트의 시작점으로 사용할 수 있는 사전 정의된 스크립트인 템플릿
이는 다음 형식을 사용하여 카탈로그 파일의 템플릿 섹션에 정의됩니다.

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

템플릿을 사용하면 JBang은 file-refs 속성에 모든 파일의 복사본을 생성합니다.
file-ref에 {basename}이 포함되어 있으면 Jbang은 이를 생성 중인 스크립트 이름으로 바꿉니다.
file-ref가 .qute 확장자를 사용하는 경우 JBang은 Qute 템플릿 엔진을 사용합니다

다음은 바로 사용할 수 있는 일부 템플릿의 예입니다.

  • picocli를 사용하는 CLI 스크립트: jbang init -t cli hellocli.java
  • Quarkus 단일 파일 REST API: jbang init -t qrest helloqrest.java

커뮤니티에서 공유하는 인터넷의 템플릿을 사용할 수도 있습니다.
예를 들어, 이 명령은 JUnit 단위 테스트 파일인 jbang init -t junit@jbangdev file_to_test.java를 생성합니다.
명령을 통해 jbangdev/jbang-catalog 저장소에서 템플릿을 정의한 jbang-catalog.json을 찾을 수 있습니다.

/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

앱스토어

JBang App Store는 색인화된 카탈로그의 별칭을 찾아볼 수 있는 웹 앱입니다.
복잡한 설정이나 설치 과정 없이 다양한 도구와 유틸리티를 검색하고 사용할 수 있는 편리한 방법을 제공합니다.
예를 들어, yostane을 검색하면 내가 다른 카탈로그에 정의한 다른 별칭을 찾을 수 있습니다.
다음 이미지는 검색 결과를 보여줍니다.

JBang, the missing scripting tool of the Java ecosystem

다음은 App Store에서 검색하여 찾은 흥미롭고 재미있는 스크립트입니다.

  • 카우세이. 다음은 스크립트 실행의 몇 가지 예입니다.
    • jbang cowsay@ricksbrown/cowsay 무!
    • jbang cowsay@ricksbrown/cowsay -f Dragon "나는 벨도라 템페스트입니다!"
  • grep과 같은 하위 문자열 찾기: jbang grep@a-services "hello" .
  • 이미지에서 PDF 만들기: Images2pdf@a-services. 다음 명령은 두 개의 이미지에서 PDF 파일을 생성합니다.
///usr/bin/env jbang "<pre class="brush:php;toolbar:false">  {
    "catalogs": {},
    "aliases": {
      // aliases
    },
    "templates": {
      // templates
    }
  }
로그인 후 복사
" "$@" ; exit $? //DEPS com.github.lalyos:jfiglet:0.0.9 import com.github.lalyos.jfiglet.FigletFont; public class DependenciesDemo { public static void main(String... args) throws Exception { System.out.println(FigletFont.convertOneLine("JBang is amazing")); } }

카탈로그를 게시하면 다음번 Jbang AppStore 인덱싱 이후에 나타날 가능성이 높습니다.
여기에 정의된 예정된 GitHub 작업입니다.

주목할만한 프레임워크가 포함된 몇 가지 예

JBang을 사용하면 널리 사용되는 프레임워크와 라이브러리를 사용하는 단일 파일 애플리케이션을 만들 수 있습니다.
몇 가지 예로는 Quarkus, picolcli 및 JavaFX가 있습니다.
다음 섹션에서 몇 가지 예를 살펴보겠습니다.

JavaFX(openjfx)

JavaFX는 데스크톱 및 UI 프레임워크입니다.
공식 웹사이트는 openjfx.io이며 추가 UI 구성 요소를 제공하고 JavaFX에 모바일 앱 지원을 제공하는 Gluon에서도 지원됩니다.
Jbang은 이 프레임워크를 지원하며 서명 파일 JavaFX 애플리케이션을 만드는 데 사용할 수 있습니다.

다음은 Jbang으로 만든 JavaFX 앱의 몇 가지 예입니다.

  • 기본창
  • 더 아름다운 예시 jbang https://gist.github.com/FDelporte/c69a02c57acc892b4c996a9779d4f830
  • 템플릿 jbang init -t javafx@yostane hellojfx

쿼커스

Quarkus는 Kubernetes 및 서버리스 환경에 최적화된 Java 프레임워크입니다.
빠른 부팅 시간과 낮은 메모리 소비를 제공하므로 클라우드 네이티브 애플리케이션에 이상적입니다.

JBang 덕분에 이 프레임워크의 기능을 활용하는 단일 파일 Quarkus 애플리케이션을 만들 수 있습니다.
다음 예에서는 문자열이 회문인지 테스트하는 나머지 API를 보여줍니다. JSON 구문 분석, 로깅 기능이 있으며 OpenAPI 및 Swagger 문서를 제공합니다.

> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

스크립트에서 //SOURCES PalindromeService.java 줄을 볼 수 있습니다.
이는 Jbang에게 스크립트와 동일한 디렉토리에서 PalindromeService.java라는 파일을 찾도록 지시합니다.
이는 Jbang이 다중 파일 스크립트를 지원한다는 것을 의미합니다.

jbang palqrest@yostane/cours-java로 서버를 실행하고, 컬 http://localhost:8080/palindrome?input=madam으로 엔드포인트를 호출할 수 있습니다.

> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다른 언어

JBang은 Java, Kotlin, JShell 및 Groovy 코드 실행을 지원합니다.
마크다운 파일에서 Java 코드를 실행할 수도 있습니다.
다음은 다양한 언어로 Jbang을 사용하는 방법에 대한 몇 가지 예입니다.

  • Kotlin: jbang init -t hello.kt filename.kt를 사용하여 Kotlin 스크립트를 초기화할 수 있습니다. 이는 공식 .main.kts Kotlin 스크립트와 다르다는 점에 유의하세요. 실제로 Jbang에서 만든 Kotlin 스크립트는 카탈로그 및 App Store 기능의 이점을 누릴 수 있습니다. 다음은 Jbang으로 만든 Kotlin 스크립트의 예입니다.
> jbang init helloworld.java
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • 흥미로운 사실: JBang의 아이디어는 Kotlin 생태계를 타겟으로 하는 kscript에서 나왔습니다.
  • Kotlin은 이미 기본 스크립팅 지원(.main.kts 스크립트 포함)을 갖추고 있지만 카탈로그, 템플릿, App Store 기능이 부족한 것 같습니다.
    • Groovy: jbang init -t hello.groovy filename.groovy를 사용하여 Groovy 스크립트를 초기화합니다. 다음은 Jbang으로 작성된 Groovy 스크립트의 예입니다.
> jbang helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • JShell: JBang은 jbang -c 'System.out.println("Inline Java 🔥 yay!")'을 사용하여 .jsh 또는 .jshell 확장자를 가진 JShell 스크립트와 인라인 스크립트를 지원합니다. 다음은 Jbang으로 생성된 JShell 스크립트의 예입니다.
///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }
  • Java 및 JShell 코드 블록을 사용한 마크다운: jbang my_markdown.md를 사용하여 마크다운 파일에서 직접 Java 및 JShell 코드 블록을 실행할 수 있습니다.
/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
로그인 후 복사
로그인 후 복사
로그인 후 복사
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

위 내용은 Java 생태계에서 누락된 스크립팅 도구인 Jbang의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿