728x90

오류

FAILURE: Build failed with an exception.

* What went wrong:

Execution failed for task ':test'.

> There were failing tests. See the report at: file:////C:/Users/...(내 파일명)

* Try:

Run with --scan to get full insights.

BUILD FAILED in 14s


해결방법

이 오류가 발생하는 원인부터 파악하자면..

1. 파일 경로 중 한글명이 포함된 경우

2. gradle 실행시 Exception 발생

3. Gradle 버전 문제

4. Windows에서 사용하는 한글 인코딩과 JVM에서 사용하는 파일 인코딩이 달라 발생한 문제

 

이렇게 4가지가 있을 수 있다. 

 

1번 문제같은 경우는 파일 경로 중 한글명이 없도록 수정하면 해결된다. --> 나같은 경우..

2번 문제같은 경우

(2.1) ctrl+alt+s를 눌러 settings 를 들어가거나 or [settings -> Build,Execution, Deployment -> Gradle] 들어간다.

(2.2) [Run tests using]을  Gradle -> intellij로 바꿔주면 된다.

3번 문제같은 경우 Gradle 버전이 5이상부터 가능하다고 해서 그래들 버전을 확인하고 버전이 낮다면 업그레이드 해주면 된다. [gradle --version]

4번 문제같은 경우 gradle build 관련 오류 질문 드립니다(TestSuiteExecutionException) - 인프런 (inflearn.com)이 링크를 보면 될 것 같다.

 

 

 

ㅎㅎ이제 한글이 있는 파일 경로로 프로젝트를 진행하지 말자....

728x90
728x90

드디어 멋사에서 spring에 대해서 배우기 시작했는데 

빌드 도구를 Maven으로 선택할지, Gradle로 선택할지에 대해 무조건 Graclle로 선택해서 둘의 차이점이 궁금해졌다.


1. 빌드 관리 도구란?

  • 우리가 프로젝트에서 작성한 java 코드와 프로젝트 내에 필요한 각종 xml, properties, jar 파일들을 JVM이나 WAS가 인식할 수 있도록 패키징 해주는 빌드 과정 == "빌드 자동화 도구" 라고 할 수 있다!
  • 프로젝트 생성, 테스트 빌드, 배포 등의 작업을 위한 전용 프로그램이라 할 수 있다.

  • 애플리케이션을 개발하면서, 일반경로로 개발에 필요한 다양한 외부 라이브러리들을 다운로드하고, 해당 라이브러리를 사용하여 개발해야하는 상황이 많다.
  • 이 때 각 라이브러리들을 번거롭게 모두 다운받을 필요없이, 빌드도구 설정파일에 필요한 라이브러리 종류와 버전들, 종속성 정보를 명시하여 필요한 라이브러리들을 설정파일을 통해 자동으로 다운로드 해주고 이를 간편히 관리해주는 도구이다.


2. Maven

  • Maven은 Java용 프로젝트 관리도구로 Apache의 Ant 대안으로 만들어졌다.
  • 빌드 중인 프로젝트, 빌드 순서, 다양한 외부 라이브러리 종속성 관계를 pom.xml파일에 명시한다.
  • Maven은 외부저장소에서 필요한 라이브러리와 플러그인들을 다운로드 한 다음, 로컬시스템의 캐시에 모두 저장한다.
  • 예를 들어, "Spring Boot Data JPA Starter" 모듈을 사용하여 프로젝트를 개발하고 싶다면 메이븐 레포지토리에서 해당 모듈을 검색하여 xml 설정파일에 추가하여 사용할 수 있다. (참고로 maven용 코드 이외에도 gradle용 코드도 탭에 있다.)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.2.4.RELEASE</version>
</dependency>

 

3. Gradle

  • Apacahe Maven과 Apache Ant에서 볼수 있는 개념들을 사용하는 대안으로써 나온 프로젝트 빌드 관리 툴이다. (완전한 오픈소스)
  • Groovy 언어를 사용한 Domain-specific-language를 사용한다. (설정파일을 xml파일을 사용하는 Maven보다 코드가 훨씬 간결하다.)
  • 2007년에 처음 개발되었고, 2013년에 구글에 의해 안드로이드 프로젝트의 빌드 시스템으로 채택되었다.
  • 꽤 큰규모로 예상되는 multi-project 빌드를 도울 수 있도록 디자인되었다.
  • Gradle은 프로젝트의 어느부분이 업데이트되었는지 알기 때문에, 빌드에 점진적으로 추가할 수 있다.
  • -> 업데이트가 이미 반영된 빌드의 부분은 즉 더이상 재실행되지 않는다. (따라서 빌드 시간이 훨씬 단축될 수 있다!)

 


4. Maven VS Gradle

  • 두 시스템이 빌드에 접근하는 방식에는 몇 가지 근본적인 차이점이 있다.
  • Gradle은 작업 의존성 그래프를 기반으로하는 반면, Maven은 고정적이고 선형적인 단계의 모델을 기반으로한다고 한다.
  • 성능 측면에서는 둘 다 다중 모듈 빌드를 병렬로 실행할 수 있지만, Gradle은 어떤 task가 업데이트되었고 안되었는지를 체크하기 때문에 incremental build를 허용한다. 이미 업데이트된 테스크에 대해서는 작업이 실행되지 않으므로 빌드 시간이 훨씬 단축된다.
    -> 빌드 설정 규모가 점점 커지면 커질수록, 빌드시간의 차이도 Maven과 비교하여 꽤 격차가 벌어질 수 있을것같다.
  • maven 의 경우 멀티 프로젝트에서 특정 설정을 다른 모듈에서 사용하려면 상속을 받아야 하지만, gradle 은 설정 주입 방식을 제공한다.
  • ​또한 Gradle은 concurrent에 안전한 캐시를 허용한다.
    -> 2개 이상의 프로젝트에서 동일한 캐시를 사용할 경우, 서로 overwrite되지 않도록 checksum 기반의 캐시를 사용하고, 캐시를 repository와 동기화시킬 수 있다.

  • ​고도로 사용자 정의된 빌드를 작성하기 위해서는 커스터마이징이 간편한 Gradle을 사용하는게 훨씬 낫다.
  • 아래 비교 예시 코드를 보면 확실히 와닿는느낌.
  • 위 내용만 보면, 속도나 캐시 사용 안전성에 대하여 당연히 Gradle로 사용하는게 이득이겠다는 생각이 든다.
  • Maven으로 설정된 프로젝트는 Gradle로 마이그레이션 할 수 있다고 한다.
  • 아래 코드를 통해 비교해보면

아래는 Maven 코드이다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.programming.mitra</groupId>
    <artifactId>java-build-tools</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

 

프로젝트에 기본으로 테스트 도구인 JUnit 라이브러리를 의존성 리스트에 추가하고 빌드 도구로 maven을 설정하였다.

mvn package

위 메이븐 설정 정보를 기반으로 JAR file로 빌드하기 위해 위와 같이 Maven 명령어를 실행한다.

이제, Maven에서 추가한 JUnit에 몇가지 플러그인 (Maven CheckStyle, FindBugs 및 PMD)을 추가해보면,

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.12.1</version>
    <executions>
        <execution>
            <configuration>
                <configLocation>config/checkstyle/checkstyle.xml</configLocation>
                <consoleOutput>true</consoleOutput>
                <failsOnError>true</failsOnError>
            </configuration>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>2.5.4</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Gradle에선 이러한 복잡하고 장황한 코드를 간결하게 만들어준다. (매우 간-결-, 가독성 상승)

apply plugin:'java'
apply plugin:'checkstyle'
apply plugin:'findbugs'
apply plugin:'pmd'
version ='1.0'
repositories {
    mavenCentral()
}
dependencies {
    testCompile group:'junit', name:'junit', version:'4.11'
}

위의 Gradle 설정에 기반하여 빌드 task를 실행하려면 아래와 같이 gradle 명령을 사용하면 된다.

 

gradle tasks --all

 

728x90
728x90

프로젝트에 대해 각각 레포를 만들면 갯수가 너무 많아져서 하나의 레포에 여러개의 프로젝트를 관리해야겠다고 필요성을 느꼈다.!!



1. GitHub에 아무것도 없는 빈 레포를 하나 만든다.

  • 부모 레포 역할을 함 
  • 처음 한번만 하면 됨
  • 나는 lion_10이라는 부모 레포를 만들었다.

 

2. 로컬에서 편한 위치에서 명령창(git bash here) 열고 아래 명령어 작성한다.

  • 이때 부모 레포가 비어진 경우 '빈 레포를 클론한 것 같다' 라는 경고 문구가 뜨지만 무시~~
git init
git clone <부모 레포 주소>

 

 

3. 만든 부모 레포로 이동하기

cd 부모 레포

 

 

 

4. 자식 레포들을 remote로 등록한다.

 git remote add <remote name> <자식 git 주소>
  • 나는  chat, sql, java 라는 이름으로 자식 레포를 등록했다.
  • git remote -v 명령어를 통해 잘 등록되었는지 remote를 확인해본다.

 

 

5. subtree를 이용하여 부모 레포에 자식 레포를 더해준다.

git subtree add --prefix=<깃에 저장될 폴더 이름> <자식 remote 이름> <branch명>​
  • <깃에 저장될 폴더 이름>은 깃에서 보여질 폴더의 이름을 설정하는 것이다. 
  • <자식 remote 이름>은 위에서 설정한 자식들의 remote를 지정하면 된다.
  • <branch 명>은 부모의 레포의 브랜치명을 작성하면 된다. 
  • 이때 부모 레포가 아무 커밋이 없는 경우
    'ambigous argument 'HEAD': unknown revision or path not in the working tree.'
    라는 오류가 뜰 수 있다.
  • 해결 방안 :
git commit --allow-empty -n -m "커밋메시지"

 

 

 

 

6. 깃에 push

git push

만약, git push를 했는데 오류가 난다면 기존에 데이터가 손실될 수 있기에 경고해주는 에러이다.
이는 아래 명령어를 이용하여 push한다. 

git push origin +main

 

 


* 이후에 프로젝트를 올릴 때는 아래처럼 하면 된다!!!

git clone <부모 리포지토리 주소>
cd <부모 리포지토리 이름>
git subtree add --prefix=<폴더 이름> <자식 리포지토리 주소> <branch명>
git commit -m "커밋 메시지"
git push
728x90
728x90

JOIN

  • JOIN 이란 - 하나 이상의 테이블로부터 연관된 데이터를 검색해 오는 방법

Cartesian Join

  • Join에 대한 조건이 생략되거나 잘못 기술되어 한 테이블에 있는 모든 행들이 다른 테이블에 있는 모든 행들과 Join이 되어서 얻어진 경우를 Cartesian Product라 한다.
  • 두 테이블의 합집합이라 생각하면 된다.
  • select * from employees, departments;
  • Cartesian Product를 얻지 않기 위해서 반드시 WHERE 절을 써 준다.
  • (JOIN 하는 테이블의 수 - 1) 개의 JOIN 조건이 필요하다.

Simple Join

SELECT t1.col1, t1.col2, t2.col1 ... FROM Table1 t1, Table2 t2
WHERE t1.col3 = t2.col3
  • FROM 절에 필요로 하는 테이블을 모두 적는다.
    • 컬럼 이름의 모호성을 피하기 위해 테이블 이름으로 직접 지칭 가능 (어느 테이블에 속하는지 알 수 없는 경우가 있을 수 있으므로 Table 이름에 Alias 사용)
    • 적절한 Join 조건을 Where 절에 부여 (일반적으로 테이블 개수 -1 개의 조인 조건이 필요)
    • 일반적으로 PK와 FK간의 = 조건 이 붙는 경우가 많다.

Join 종류

종류 설명

Cross Join (Cartesian Product) 모든 가능한 쌍이 나타남
Inner Join 조건을 만족하는 튜플만 나타남
Outer Join Join 조건을 만족하지 않는 튜플 (짝이 없는 튜플)도 null과 함께 나타남
Theta Join 조건(theta) 에 의한 조인 / (FK가 아닌 다른걸 이용 ?)
Equi-Join Theta Join & 조건이 Equal (=)
Natural Join Equi-Join & 동일한 Column 명 합쳐짐
Self Join 자기 자신과 조인

EQUI-JOIN

  • 컬럼에 있는 값이 정확하게 일치하는 경우에 = 연산자를 사용하여 JOIN
SELECT 테이블명.컬럼명, 테이블명.컬럼명. …
FROM 테이블1, 테이블2
WHERE 테이블1.컬럼1 = 테이블2.컬럼2
  • 테이블명.컬럼명 - 검색해올 데이터가 어디에서 오는지 테이블과 컬럼을 밝혀둔다.
  • 테이블1.칼럼1 = 테이블2.컬럼2 - 두 테이블 간에 논리적으로 값을 연결시키는 칼럼 간의 조건을 기술한다.

EQUI-JOIN의 문형

  • 컬럼에 있는 값들이 정확히 일치하는 경우에 = 연산자를 사용해서 조인
  • 일반적으로 PK-FK 관계에 의하여 JOIN이 성립
  • WHERE절 or ON절을 이용
  • 액세스 효율을 향상시키고 좀 더 명확히 하기 위해 칼럼이름 앞에 테이블 이름을 밝힌다.
  • 같은 이름의 칼럼이 조인대상 테이블에 존재하면 반드시 테이블 이름을 밝혀줄 것 !
  • JOIN을 위한 테이블이 N개라 하면, JOIN을 위한 최소한의 = 조건은 N-1 이다.
# 사원 이름과 부서명을 출력하라.
select emp.ename, dept.dname from emp, dept;
select e.ename, d.dname from emp e, dept d;
select ename, dname from emp e, dept d;

# 중복되는 컬럼명 앞에는 반드시 테이블을 명시해야함
select ename, dname, e.deptno from emp e, dept d;

select e.ename, d.dname from emp e, dept d
where e.deptno = d.deptno;

# 모든 사원의 사번, first_name, email, department_name을 조회하라
select e.employee_id, e.first_name, e.email, d.department_name
from employees e, departments d
where e.department_id = d.department_id;

추가적인 조건 기술

  • WHERE 절에 JOIN 조건 이외의 추가적인 조건을 가질 수 있다.
  • 조인을 만족하는 데이터 중 특정 행만 선택하여 결과를 얻고 싶을 때 추가조건을 AND로 연결한다.
  • 사원의 이름과 부서명을 출력하라. 단, location_id 가 1800인 경우만 출력하라.
  • select concat(e.first_name, ' ', e.last_name) as 이름, d.department_name, l.city from employees e, departments d, locations l where e.department_id = d.department_id and d.location_id = l.location_id and l.location_id = 1800;

조건(theta) Join

  • 임의의 조건을 Join 조건으로 사용가능
  • Non-Equi Join 이라고도 한다.
  • # 이름, 급여, 등급을 조회하라 select e.ename, e.sal, s.grade from emp e, SALGRADE s where e.sal BETWEEN s.LOSAL AND s.HISAL;

Natural Join

  • 두 테이블에 공통 칼럼이 있는 경우 별다른 조인 조건없이 공통 칼럼처럼 묵시적으로 조인이 되는 유형
  • ANSI / ISO SQL1999를 따르는 ANSI JOIN 문법
select e.ename, d.dname
from emp e natural join dept d;

문제점

  • 조인하고자 하는 두 테이블에 같은 이름의 칼럼이 많을 때, 위와 같을 시 특정한 칼럼으로만 조인하고 싶다면 USING 절을 사용해서 기술한다.
  • select e.ename, d.dname from emp e join dept d using(deptno);

INNER JOIN - JOIN ~ ON

  • 공통된 이름의 칼럼이 없는 경우 가장 보편적으로 사용할 수 있는 유형이다.
  • WHERE 절에 일반조건만 쓸 수 있게하고, 조인 조건은 ON에 두어 보다 의미를 명확히 하고 알아보기도 쉽다.
  • ON 부분을 WHERE 절에서 작성 가능하다.
  • select e.ename, d.dname from emp e join dept d on (e.deptno = d.deptno) where d.deptno = 20 ;

Outer Join

  • Join 조건을 만족하지 않는(짝이 없는) 튜플의 경우 Null을 포함하여 결과를 생성
  • 모든 행이 결과 테이블에 참여

종류

  • Left Outer Join - 왼쪽의 모든 튜플은 결과 테이블에 나타남
  • Right Outer Join - 오른쪽의 모든 튜플은 “”
  • Full Outer Join - 양쪽 모두 결과 테이블에 참여

→ 왼쪽 테이블의 Null 값을 포함하는 튜플도 모두 보고 싶어요 : Left Outer Join

  • 오라클의 경우, NULL이 올 수 있는 쪽 조건에 + 를 붙여준다.
select e.ename, d.dname
from emp e left outer join dept d using(deptno); # 왼쪽의 모든 튜플

select e.ename, d.dname
from emp e right outer join dept d using(deptno); # 오른쪽의 모든 튜플

select e.ename, d.dname
from emp e left outer join dept d using(deptno)
union
select e.ename, d.dname
from emp e right outer join dept d using(deptno); # 양쪽 모든 튜플
  • MySQL의 경우, FULL OUTER JOIN이 아닌 UNION 연산을 통해 가능하다.

JOIN 문법 정리

SELECT table1.column, table2.column
FROM table1

[CROSS JOIN table2] |

[NATURAL JOIN table2] |

[JOIN table2 USING (column_name)] |

[JOIN table2
ON(table1.column_name = table2.column_name)] | [LEFT|RIGHT|FULL OUTER JOIN table2
ON (table1.column_name = table2.column_name)];
  • left outer → left / right outer → right 로 축약해서 사용가능

SELF JOIN

  • 하나의 테이블을 서로 다른 테이블로 생각하여 JOIN 하는 것
# 사원이름과 매니저 이름을 출력하라.
select e.ename 사원명, m.ename 매니저이름
from emp e, emp m
where e.mgr = m.empno;

# 사원이름, 매니저 이름을 출력하세요. 단, 매니저가 없는 사원도 출력하시오.
select e.ename 사원명, m.ename 매니저이름
from emp e
left outer join emp m
on e.mgr = m.empno;

🔎 SubQuery

  • 하나의 SQL 질의문 속에 다른 SQL 질의문이 포함되어 있는 형태
  • 쿼리 하나로는 원하는 결과를 얻어내지 못하는 경우에 사용
# SMITH가 속한 부서의 급여 평균을 알고 싶다.
# 1. 스미스의 부서 번호는?
# 2. 해당 부서 번호의 급여 평균

select avg(sal)
from emp
where deptno = (select deptno from emp where ename = 'SMITH');
  • ✔ 서브쿼리 짜는 것을 익히기 위해선 각 조건들을 작은 단위로 (쿼리 하나씩) 뽑아내는 연습을 하는 것이 좋겠다.

Single-Row Subquery

  • Subquery의 결과가 한 개의 ROW인 경우
  • Single-Row Operator 를 사용해야 함 - = , > , >= , < , <= , <>
# 사원의 평균 급여보다 작은 급여를 받는 사원의 이름과 급여를 출력
select ename, sal
from emp
where sal < (select avg(sal)
             from emp);

# 부서이름이 SALES인 부서의 사원 이름과 부서 번호를 출력
select ename, deptno
from emp
where deptno = (select deptno
                from dept
                where dname = 'SALES');

Multi-Row SubQuery (Feat. IN, ANY, ALL)

  • Subquery의 결과가 둘 이상의 ROW
  • Multi-Row에 대한 연산을 사용해야 함 - ANY , ALL , IN , EXIST …
# 아래의 경우는 오류가 발생한다.
SELECT *
FROM emp
WHERE ename = (SELECT MIN(ename)
               FROM emp GROUP BY deptno);

# 아래와 같이 in 연산을 사용하여 그룹 내에 있는지
# 확인하는 식으로 사용해야 한다.
SELECT *
FROM emp
WHERE ename in ('KANG', 'CLARK', 'ADAMS', 'ALLEN');

# 따라서 다음과 같이 해결할 수 있다.
SELECT *
FROM emp
WHERE ename in (SELECT MIN(ename)
               FROM emp GROUP BY deptno);

ANY

  • 다수의 비교값 중 한개라도 만족하면 true
  • IN 과 다른 점은 비교 연산자를 사용한다는 점
  • SELECT ename, sal, deptno FROM emp WHERE ename = ANY (SELECT MIN(ename) FROM emp GROUP BY deptno); # 아래 쿼리는 sal > 950 과 같은 결과이다. SELECT * FROM emp WHERE sal > ANY(950, 3000, 1250)

ALL

  • 전체 값을 비교해서 모두 만족해야만 true
  • Oracle은 오류가 발생하지 않지만, MySQL은 Subquery에서만 사용 가능하다.
  • # 아래의 쿼리는 결과가 없다. 모두를 만족할 수는 없기 때문 # MySQL에서는 값에 대해서는 ALL을 사용할 수 없다. 여기선 단지 예제일뿐 ! SELECT * FROM emp WHERE sal = ALL(950, 3000, 1250) # 결국 아래와 같이 사용된다. select * from emp where sal < all (select sal from emp where deptno in (30, 10));

Correlated Query

  • Outer Query와 Inner Query가 서로 연관되어 있다.
  • 해석방법
    • Outer query의 한 Row를 얻는다.
    • 해당 Row를 가지고 Inner Query를 계산한다.
    • 계산 결과를 이용, Outer query의 WHERE 절을 evaluate
    • 결과가 참이면 해당 Row를 결과에 포함시킨다.
# 사원의 이름, 급여, 부서 번호를 출력하시오. 단 사원의 급여가
# 그 사원이 속한 부서의 평균 급여보다 큰 경우만 출력하시오.
SELECT o.ename, o.sal, o.deptno
FROM emp o
WHERE o.sal > (SELECT AVG(i.sal)
               FROM emp i
               WHERE i.deptno = o.deptno);

# 각 부서별로 최고 급여를 받는 사원을 출력하라.
# 1
select deptno, empno, ename, sal
from emp
where (deptno, sal) in (select deptno, max(sal)
                        from emp
                        group by deptno);

# 2
select a.deptno, a.empno, a.ename, a.sal
from emp a,
     (select b.deptno, max(b.sal) msal
      from emp b
      group by deptno) c
where a.deptno = c.deptno
  and a.sal = c.msal;

# 3
SELECT deptno, empno, ename, sal
FROM emp e
WHERE e.sal = (SELECT max(sal)
               FROM emp WHERE deptno = e.deptno);

Set Operator

  • 두 질의의 결과를 가지고 집합 연산
  • UNION , UNION ALL , INTERSECT , MINUS
  • 우선 임의로 테이블 생성 a : {1, 2, 3} / b : {2, 3, 4}
  • create table a ( name int ); create table b ( name int ); insert into a value ('1'); insert into a value ('2'); insert into a value ('3'); insert into b value ('2'); insert into b value ('3'); insert into b value ('4');
# UNION : 합집합 (중복 제거)
select * from a union select * from b;
# UNION ALL : 합집합 (중복 포함)
select * from a union all select * from b;
# INTERSECT : 교집합
# - MySQL에서는 지원하지 않는다.
select * from a intersect select * from b; # 불가
select a.name from a, b where a.name = b.name;
# minus : 차집합
# - MySql 에서 지원하지 않는다.
select * from a minus select * from b;
select a.name from a where a.name not in (select b.name from b);

RANK() 함수

  • 요소에 대해 순서를 매기는 함수
  • MySQL 8 이상에서 사용가능
SELECT sal, ename,
			rank() over(order by sal desc) AS ranking
FROM emp;

 

728x90
728x90

Final

1-1. final 클래스

  • 자바에서 final 클래스는 다른 클래스가 그것을 상속받을 수 없게 하는 특별한 종류의 클래스이다.
  • final 키워드를 클래스 선언에 추가함으로써, 해당 클래스는 ‘최종적’이며 변경할 수 없다는 것을 의미한다.

final 클래스의 필요성

  1. 불변성 보장
    • 클래스가 일단 생성되면 그 상태가 변경되지 않도록 함으로써, 안정성과 보안을 향상시킨다.
  2. 상속 방지
    • 특정 클래스의 설계와 구현이 그대로 유지되어야 할 때 중요하다.
  3. 불변 클래스 생성
    • final 클래스는 불변 객체를 만드는 데 유용한다.
    • 불변 객체는 생성 후 그 상태가 변경되지 않으므로, 여러 면에서 프로그램의 신뢰성을 높일 수 있다.
  4. 성능 최적화
    • 컴파일러와 JVM은 final 클래스에 대해 성능 최적화를 수행할 수 있다.
    • final 클래스의 메소드는 오버라이딩되지 않기 때문에, 컴파일 타임에 메소드 호출이 결정될 수 있어, 실행 시간이 단축될 수 있다ㅏ.

final 클래스의 특성

  • 확장 불가능
    • 다른 클래스는 final 클래스를 상속받을 수 없다.
    • → 이는 final 클래스의 모든 메소드가 상속되거나 오버라이딩될 수 없음을 의미한다.
  • 메소드 오버라이딩 방지
    • final 클래스 내의 모든 메소드는 자동으로 final 로 간주된다.

💡 final 클래스는 코드의 안정성과 유지 보수성을 높이는 데 기여할 수 있으며, 특정한 사용 사례에서 중요한 역할을 한다. 클래스의 설계 의도를 명확히 하고, 불필요한 상속과 변경을 방지하여 프로그램의 견고성을 높이고자 할 때 final 클래스를 사용하는 것이 좋다.


1-2. final 클래스 예제

final class SecurityConfig {
    private static final String ENCRYPTION_KEY = "ComplexKey123!";

    private SecurityConfig() {
				// 생성자를 private으로 선언하여 외부에서 인스턴스화 방지
    }

    public static String getEncryptionKey() {
        return ENCRYPTION_KEY;
    }
}

public class FinalEx {
    public static void main(String[] args) {
        String encryptionKey = SecurityConfig.getEncryptionKey();
        System.out.println("암호화 키: " + encryptionKey);
    }
}
  • SecurityConfig 클래스 : final 로 선언되어 있어 상속 불가능
  • Private 생성자 : 클래스 외부에서 인스턴스를 생성할 수 없다.
  • 클래스가 유틸리티 목적으로만 사용되도록 의도된 것
  • Main 클래스 : SecurityConfig 클래스의 정적 메소드를 호출하여 암호화 키를 가져옴
  • 이 예제는 final 클래스를 사용하여 클래스의 불변성을 보장하고, 보안 관련 중요한 설정이 외부에서 변경되는 것을 방지하는 방법을 보여준다.

1-3. Java JDK의 final 클래스

  • JDK 내에서 final 클래스의 사용은 주로 안정성과 불변성을 확보하기 위해 이루어진다.
  • (변경되어서는 안되는 중요한 클래스들이 포함)
  • java.lang.String , java.lang.Math , java.lang.System , java.util.Collections 등
  • → 정적 메소드만 사용가능

2-1. final 필드

  • 자바에서 final 필드는 한 번 초기화되면 그 값을 변경할 수 없는 필드를 의미한다.
  • 상수를 정의하거나, 객체의 불변성을 보장하는 데 사용

final 필드의 필요성

  1. 상수 정의
    • 수학적 상수, 설정 값 등 프로그램 전반에 걸쳐 일관되게 사용되어야 하는 값들을 final 필드로 정의
  2. 불변 객체 생성
    • 객체의 불변성을 보장하려면, 객체가 생성된 후에는 그 상태가 변경되지 않도록 해야함
    • → 객체의 예측 가능성과 신뢰성을 높인다.
  3. 스레드 안정성
    • 멀티스레딩 환경에서 final 필드는 스레드 간의 안전한 읽기 작업을 보장한다.
    • 한 번 초기화된 final 필드의 값은 변경되지 않으므로, 스레드 간에 동기화 없이 안전하게 읽을 수 있다.
  4. 메모리 가시성 보장
    • 객체가 생성될 때 한 번만 쓰여지고, 이후에는 변경되지 않기 때문에, JVM은 메모리 가시성을 보장한다.
    • 즉, final 필드의 값은 모든 스레드에게 일관되게 보여진다.

final 필드의 특성

  • 초기화 제한
    • final 필드는 선언 시 또는 생성자에서만 초기화할 수 있다.
  • 객체의 핵심 속성 보호
    • 객체가 특정한 상태를 유지해야 할 때, 예를 들어 설정 값이나 중요한 데이터를 final 필드로 선언함으로써, 해당 값의 무결성을 유지할 수 있다.

💡 final 필드는 프로그램의 안정성과 무결성을 높이는 중요한 방법이다. 이러한 필드는 프로그램이 더욱 견고하고 안정적으로 동작하도록 돕고, 예측 가능한 동작을 보장하는 데 기여한다.


2-2. final 필드 예제

class Person {
    private final int id;
    private String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class FinalFieldEx {
    public static void main(String[] args) {
        Person person = new Person(1001, "John Doe");
        System.out.println("사람의 ID: " + person.getId());
        System.out.println("사람의 이름: " + person.getName());

        person.setName("Jane Doe");
        System.out.println("변경된 이름: " + person.getName());
    }
}
  • Person 클래스, 생성자
    • Person 객체가 생성될 때, 식별 번호와 이름은 생성자를 통해 초기화된다. 식별 번호는 final 필드이므로, 이후에는 변경 불가

3-1. final 메소드

  • 한 번 선언되면 하위 클래스에서 오버라이딩(재정의)할 수 없다.
  • → 클래스의 핵심적인 기능을 안정적으로 유지하기 위해 사용된다.

final 메소드의 필요성

  1. 메소드의 무결성 보장
    • final 메소드는 변경되거나 재정의될 수 없다.
  2. 오버라이딩 방지
  3. 보안 강화
  4. 예측 가능한 동작
    • 개발자는 final 메소드가 항상 동일한 방식으로 동작한다는 것을 알고 있으므로, 의도치 않은 오류나 버그를 줄일 수 있다.

final 메소드의 특성

  • 재정의 불가능
  • 클래스의 동작 보호

💡 final 메소드는 객체 지향 프로그래밍에서 클래스의 기능을 보호하고, 안정적인 동작을 보장하는 중요한 도구이다. 이는 프로그램의 견고성을 높이고, 예상치 못한 동작으로부터 시스템을 보호하는 데 중요한 역할을 한다.


3-2. final 메소드 예제

class BankAccount {
    private final int accountNumber;
    private double balance;

    public BankAccount(int accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public final String getAccountInfo() {
        return "계좌 번호: " + accountNumber + ", 잔액: " + balance;
    }

    public void deposit(double amount) {
        balance += amount;
    }

    public void withdraw(double amount) {
        balance -= amount;
    }
}

public class FinalMethodEx {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(12345, 1000.0);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1000.0
        account.deposit(500);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1500.0
        account.withdraw(200);
        System.out.println(account.getAccountInfo());   // 계좌 번호: 12345, 잔액: 1300.0
    }
}
  • final 메소드는 클래스의 동작을 안정적으로 유지하고, 프로그램의 신뢰성을 향상시키는 데 기여한다.
728x90

'Spring > TIL - 멋쟁이사자처럼' 카테고리의 다른 글

TIL - 3월 27일 : HTML  (1) 2024.03.29
728x90

String 클래스

== 와 equals()

  • == : 비교하는 두 대상의 주소값을 비교
  • equals() : 비교하는 두 대상의 값을 비교
public class StringExam {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        String str3 = new String("hello");
        String str4 = new String("hello");

        System.out.println(str1 == str2);      // true
        System.out.println(str1.equals(str2)); // true

        System.out.println(str2 == str3);      // false
        System.out.println(str2.equals(str3)); // true

        System.out.println(str3 == str4);      // false
        System.out.println(str3.equals(str4)); // true
    }
}

추상 클래스

  • abstract 키워드를 사용하여 클래스를 정의한다.
  • 확장 만을 위한 용도로 정의되는 클래스
  • 추상 클래스는 인스턴스가 될 수 없다.
  • 추상 클래스를 상속받는 자손이 인스턴스가 된다.
  • 추상 클래스는 보통 1개 이상의 추상 메소드를 가진다. (없어도 오류 발생은 X)
public abstract class 클래스명 { ... }

추상 메소드

  • 추상 메소드는 메소드에 대한 구현을 가지지 않는다.
  • 추상 클래스의 자식 클래스가 해당 메소드를 구현 하도록 강요하기 위해 존재
  • 추상 메소드는 추상 클래스에만 조재할 수 있다.

✔ 추상 클래스를 사용하는 이유

  1. 공통된 필드와 메서드를 통일할 목적
    • 필드와 메서드 이름을 통일하여 유지보수성을 높이고 통일성을 유지할 수 있다.
  2. 실체 클래스 구현시, 시간절약
    • 강제로 주어지는 필드와 메서드를 가지고 실체 클래스의 성격대로 구현만 하면 된다.
    • 설계 시간이 절약되며, 구현하는데만 집중할 수 있다.
  3. 규격에 맞는 실체 클래스 구현
    • 공통된 속성은 규격에 맞게 구현할 수 있다는 의미
    • → 추상 클래스를 상속받은 실체 클래스들은 반드시 추상 메서드를 재정의해서 실행 내용을 작성해야 하기 때문
    • 그 외의 것은 자유롭게 구현이 가능하다.

중요한 것은, 소스 수정시 다른 소스의 영향도를 적게 가져가면서 변화에는 유연하게 만들기 위해 추상클래스를 사용한다는 점 !

추상클래스의 상속

  • 추상 클래스의 상속에도 extends 키워드 사용
  • 추상 클래스를 상속하는 클래스는 반드시 추상 클래스의 추상 메소드를 구현해야 함
  • 추상 클래스간의 상속에서는 추상클래스를 구현하지 않아도 됨
  • 추상 클래스의 추상 메소드를 상속받아 정의하는 예시
abstract class Shape {
    public abstract double calculateArea();
}

class Triangle extends Shape {
    private double x;
    private double y;

    public Triangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y / 2;
    }
}

class Rectangle extends Shape {
    private double x;
    private double y;

    public Rectangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y;
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        Shape triangle = new Triangle(10, 5);
        System.out.println("삼각형의 너비: " + triangle.calculateArea());

        Shape rectangle = new Rectangle(10, 20);
        System.out.println("사각형의 너비: " + rectangle.calculateArea());
    }
}
  • 추상 클래스의 연속 상속
abstract class Aclass {
	public abstract void Amethod();  // 추상 메소드
}
abstract class Bclass extends Aclass { // 추상 클래스를 상속받은 추상 클래스
	public abstract void Bmethod();
}

public class Cclass extends Bclass {
	public void Amethod() { ... } // 반드시 구현해야 함
	public void Amethod() { ... } // 반드시 구현해야 함
**}**

템플릿 메소드 패턴(Template Method Pattern)

  • 디자인 패턴 중 하나로, 알고리즘의 구조를 메소드에 정의하고,
  • 알고리즘의 일부 단계를 서브클래스에서 구현하도록 하여 알고리즘의 일부 변경을 허용하는 패턴이다.
  • → 공통의 알고리즘 과정이 있지만, 그 과정 중 일부가 클래스마다 다를 때 유용하다.
  • 추상 클래스를 사용하여 템플릿 메소드를 정의하고, 구체적인 작업은 서브클래스에서 오버라이드하여 구현

구조

  • 추상 클래스(Abstract Class)
    • 알고리즘의 단계를 정의하는 템플릿 메소드와 알고리즘의 일부를 구현하는 하나 이상의 추상 메소드로 구성
  • 구체 클래스(Concrete Class)
    • 추상 클래스를 상속받아 추상 메소드를 구현한다. (알고리즘의 일부 단계를 구체화)
abstract class BeverageRecipe {
    public **final** void prepareRecipe() {  // 템플릿 메소드
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    abstract void brew(); // 추상 메소드

    abstract void addCondiments(); // 추상 메소드

    public void boilWater() {
        System.out.println("물을 끓입니다.");
    }

    public void pourInCup() {
        System.out.println("컵에 따릅니다.");
    }
}

class Coffee extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("필터를 통해 커피를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("설탕과 우유를 추가합니다.");
    }
}

class Tea extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("차를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("레몬을 추가합니다.");
    }
}

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        BeverageRecipe tea = new Tea();
        tea.prepareRecipe();

        BeverageRecipe coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

Java Interface

개념

  • 서로 관계가 없는 물체들이 상호 작용을 하기 위해서 사용하는 장치나 시스템
  • 클래스 구조상의 관계와 상관 없이 클래스들에 의해 구현되어질 수 있는 규약

목적

  • 클래스들 사이의 유사한 특성을 부자연스러운 상속 관계를 설정하지 않고 얻어냄

활용

  • 하나 또는 그 이상의 클래스들에서 똑같이 구현되어질 법한 메소드를 선언하는 경우
  • 클래스 자체를 드러내지 않고 객체의 프로그래밍 인터페이스를 제공하는 경우

클래스 vs 인터페이스

  • 완결한 메소드(Concrete method)
    • 메소드의 구현을 포함한 일반적인 메소드를 concrete method라 함
    • 추상 메소드(Abstract Method)의 반대 개념

✔ 인터페이스의 상속

  • 인터페이스는 다중 상속을 지원하지 않는 자바에서 다중 상속의 장점을 활용하기 위해 도입
  • 한 클래스는 하나의 부모 클래스를 가지며 하나 이상의 인터페이스를 구현할 수 있다.
  • 인터페이스 사이에서는 다중 상속이 가능하다.
  • interface 키워드로 선언하고 implements 키워드로 사용
  • 인터페이스를 구현한 클래스에서 추상 메소드를 반드시 정의해야 함
interface Ainter {
    public void aMethod();
    public void same();
}
interface Binter extends Ainter{
    public void bMethod();
}
interface Cinter{
    public void cMethod();
    public void same();
}
interface Dinter extends Cinter, Binter{
    // 인터페이스들 간에는 다중 상속이 가능하다.
    public void dMethod();
}
class DImpl implements Dinter{
    @Override
    public void aMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void bMethod() {

    }
    @Override
    public void same() {

    }
    @Override
    public void cMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void dMethod() {
        System.out.println("aMethod 구현");
    }
}

public class InterfaceDemo{
    public static void main(String[] args) {
        // 인터페이스도 타입이다.
        Ainter ainter = new DImpl();
        Cinter cInter = new DImpl();

        // 자기가 정의한 것만 사용 가능
        ainter.aMethod();
        cInter.cMethod();

        Binter binter = new DImpl();
        Dinter dinter = new DImpl();

        binter.aMethod();
        binter.bMethod();
        binter.same();

        /* 타입이 아는 것 까지만 쓸 수 있고,
         * 외의 것을 쓰고 싶다면 형변환이 필요 */
        ((DImpl)ainter).say();
    }
}

default 메소드

  • 인터페이스가 default 키워드로 선언되면 메소드가 구현될 수 있다.
  • 또한 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.
  • 인터페이스가 변경이 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다.
  • → 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 함
interface Calculator {
    public int plus(int i, int j);

    public int multiple(int i, int j);

    default int exec(int i, int j) {  // default로 선언함으로 메소드를 구현할 수 있다.
        return i + j;
    }
}

class MyCalculator implements Calculator {
    @Override
    public int plus(int i, int j) {
        return i + j;
    }

    @Override
    public int multiple(int i, int j) {
        return i * j;
    }
}

public class CalculatorDemo {
    public static void main(String[] args) {
        Calculator cal = new MyCalculator();

        System.out.println(cal.plus(5, 10));
        System.out.println(cal.multiple(5, 10));
        
        int value = cal.exec(5, 10);
        System.out.println(value);
    }
}

인터페이스의 static

변수

  • 인터페이스에서 int a = 10; 과 같이 멤버 변수를 선언하게 되면 static final 로서 선언된다. (생략 가능, 생략 하더라도 static final 로서 선언됨)
  • 즉, 인터페이스에서 변수를 선언하게 되면, 그 변수는 상수가 된다.
  • → 상수로서 변수와 구분을 위해 대문자로 선언하는 것이 관례이다.

static 메소드

  • 인터페이스에 static 메소드를 정의하는 것은, 클래스에 static 을 정의하는 것과 동일하다.
  • 인터페이스에서 메소드 구현이 가능하다.
  • 반드시 클래스 명으로 메소드를 호출해야 한다.
728x90
728x90

문제링크
https://school.programmers.co.kr/learn/courses/30/lessons/1844


문제 핵심

1. n * m 크기의 maps가 주어지고 maps에서 0은 벽을 1은 길을 나타낸다.

2. 목표지점은 maps의 우측 하단 끝 지점이며 시작지점은 (1,1) 이다.

3. 캐릭터는 상하좌우로 움직일 수 있으며, 벽으로 이동하는 것은 불가능하다.

4. 목표지점에 도달하기 위해 최소한의 움직임을 구하기


첫 번째 방법

최단거리를 구하는 문제이기에 BFS탐색법을 사용했지만 시간 초과가 발생하였다..ㅎㅎ

def solution(maps):
    w = len(maps) - 1 
    h = len(maps[0]) - 1 
    visit = [] 
    going = [[0,0,1]] 
    while going:
        now = going.pop(0) 
        x, y, count = now[0], now[1], now[2] 
        if x == w and y == h: 
            return count
        for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]: 
            nx = x + dx
            ny = y + dy
            if 0 <= nx <= w and 0 <= ny <= h and [nx, ny] not in visit and maps[nx][ny] == 1:
            
                going.append([nx, ny, count + 1]) 
                visit.append([nx, ny]) 
    return -1

기본적인 BFS 문제는 풀이방법이 비슷하다.
1. BFS문제면 이동할 때 사방팔방 다 이동하고 그 값을 저장하는 변수 필요 => 큐 사용

2. 위로 이동하고 좌우 옆으로 이동했을 때 해당 좌우가 방문했는지 저장하는 변수 필요  => 좌, 우, 상, 하 이동

 

1. 목표지점을 계산하기 위한 maps의 세로 길이 가로 길이를 w ,h 로 정의

2. visit라는 방문한 지점을 담을 리스트 정의

3. going은 방문해야할 지점을 담을 리스트

4. now 는 현재 지점이고 x, y, count 는 현재 x, y좌표 및 이동 거리

5. 만약 목표지점일 경우 이동 거리를 리턴

6. dx, dy 에는 (1, 0), (-1, 0), (0, 1), (0, -1) 상하좌우 이동의 값을 넣고

7. 경계 및 벽에 막히지 않고, 방문한 지점이 아닐 경우 방문할 지점에 추가하고 방문한 지점에 추가

8.  모든 경로를 탐색후에도 만족하지 않으면 -1 리턴

 


그래서 뭐가 문제인가.. 알아봤는데 나는 방문한 지점을 담은 리스트 visit를 리스트로 사용했고 이 경우에서 방문 여부를 확인하는 로직인 not in을 사용할 경우 시간복잡도가 크게 상승한다는 얘기.. 이를 해결하기 위해 visit를 set로 선언하여 통과하였다.


두 번째 방법

def solution(maps):
    w = len(maps) - 1
    h = len(maps[0]) - 1
    visit = set() 
    going = [[0,0,1]]
    while going:
        now = going.pop(0)
        x, y, count = now[0], now[1], now[2]
        if x == w and y == h:
            return count
        for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
            nx = x + dx
            ny = y + dy
            if 0 <= nx <= w and 0 <= ny <= h and (nx, ny) not in visit and maps[nx][ny] == 1:
                going.append([nx, ny, count + 1])
                visit.add((nx,ny))
    return -1

set 자료형의 경우 내부 해시테이블을 이용하여 포함여부를 확인할 때 리스트보다 빠른 속도로 확인이 가능하여 시간을 줄여 해결할 수 있었다.


세 번째 방법

뭔가 내가  쓴건 깔끔하지 않다고 해야하나.. 그래서 다른 사람 코드를 봤더니

going 리스트도 deque를 사용하여 속도를 더욱 줄이는 방법이 있고 깔끔했다.

from collections import deque
def solution(maps):
    w = len(maps) - 1
    h = len(maps[0]) - 1
    visit = set()
    going = deque([[0,0,1]]) 
    while going:
        now = going.popleft()
        x, y, count = now[0], now[1], now[2]
        if x == w and y == h:
            return count
        for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
            nx = x + dx
            ny = y + dy
            if 0 <= nx <= w and 0 <= ny <= h and (nx, ny) not in visited and maps[nx][ny] == 1:
                going.append([nx, ny, count + 1])
                visit.add((nx,ny))
    return -1

deque를 사용하면 기존의 pop(), append()의 시간복잡도가 O(N)에서 popleft()를 통한 시간복잡도 O(1)로 줄어들기 때문에 n이 커질 경우 더욱 빠르게 문제해결이 가능해진다.

728x90
728x90

HTML

인터넷과 웹의 시작

미국 국방성에서 시작. 1969년 현재 인터넷의 모태가 되는 ARPANET이 개발되었다. 1989년 팀 버너스 리는 월드 와이드 웹(World Wide Wep, WWW)을 개발하였다. 문서와 문서를 연결하는 하이퍼링크(Hyper Link) 개념이 도입되었고, 1991년에 배포되었으며 1993년에 소스코드가 공개되었다.

 

웹 브라우저의 역사

  • 1993년 : 최초의 GUI 환경의 '모자이크' 탄생
  • 1996년 ~ 2008년 말 : 1차 브라우저 전쟁. 모자이크를 개발했던 마크 엔더리슨은 '넷스케이프'를, 마이크로소프트는 '인터넷 익스플로러'를 개발. 운영체제에 기본으로 탑제되어 제공되던 익스플로러가 넷스케이프를 이기고 대부분의 점유율을 확보
  • 2008년 12월 : 구글 크롬 정식 출시
  • 2010년 : 인터넷 익스플로러가 최신 표준을 지원하지 않는 문제가 발생
  • 2009년 ~ 2015년 : 2차 브라우저 전쟁. 2022년 2월 기준 데스크탑 64.89%의 점유율로 크롬이 승리

HTML5

최신 웹 기술로, 단순히 웹 문서를 작성할 때 사용되는 마크업 랭귀지(HTML)의 문법적(syntactic) 버전 뿐만 아니라 새로운 DOM API 스펙을 포함한다. 일렉트론(Electron)등의 기술을 사용하면 애플리케이션 웹 기반으로 개발이 가능하다.

 

시작 태그, 끝 태그, 내용

<h1>Hello</h1>
  • 시작 태그 : <h1>
  • 끝 태그: </h1>
  • 내용: Hello
  • 요소(element): 시작 태그 + 내용 + 끝 태그
  • 내용엔 다른 요소들이 올 수도 있다.

속성

<a href="http://www.naver.com">naver</a>

 

 

기본 구조

<!DOCTYPE html>
<html>
    <head>
        <title>문서의 제목</title>
    </head>
    <body>
        문서의 내용
    </body>
</html>

 

head

웹 브라우저에 문서 정보를 알려주는 태그. 화면에 보이는 부분은 아니다. <mata>, <title> 등이 쓰이고 스타일시트 파일도 이곳에서 연결해준다.

 

meta 태그

  1. 문자셋 정의: 문서의 문자 인코딩을 지정
<mate charset="UTF-8">

2. 뷰포트 설정: 반응형 웹 디자인에 필수적인 속성. 모바일 브라우저에서 페이지가 어떻게 보여질지 제어한다.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

3. 키워드: 페이지 내용과 관련된 키워드를 제공하고 검색엔진 최적화(SEO)에 도움이 된다.

<meta name="keywords" content="HTML, CSS, JavaScript">

4. 웹 페이지 설명: 웹 페이지의 간단한 설명을 제공. 검색엔진의 검색결과에서 페이지 아래에 표시되는 설명문

<meta name="description" content="Html 구조에 대해 설명합니다.">

이외에도 저자 설명, 리프레시 설정, 캐시 제어, 오픈 그래프 메타태그 등의 설정을 할 수 있게 해주는 태그이다.


html 태그 종류

제목

h1, h2, h3, h4, h5, h6

h1은 가장 큰 제목, h6는 가장 작은 제목

 

줄바꿈

<br />

 

가로줄

<hr />

 

앵커

하이퍼링크 태그를 의미한다. 내용 부분을 클릭하면 해당 주소로 이동

<a href="주소">내용</a>

 

글자의 모양

<b>, <i>, <small>, <sub>, <sup>, <ins>, <del>

글자의 모양은 태그를 이용하지 않고 보통 CSS를 이용하는 것이 좋다

 

목록 태그/기본 목록

<ul> 순서가 없는 목록을 표현

<ol> 순서가 있는 목록을 표현

<li> 목록의 요소

 

목록 태그/정의 목록

<dl> 정의 목록 태그

<dt> 정의 용어 태그

<dd> 정의 설명 태그

 

테이블 태그

<table> 표

<tr> 표 내부의 행

<th> 제목 셀 태그

<td> 일반 셀 태그

 

- 테이블 속성

border 표의 테두리 두께

rowspan 세로로 셀 합치기

colspan 가로로 셀 합치기

 

이미지 태그

<img> 이미지

 

- 이미지 속성

src 이미지 경로

alt 이미지 설명

width 이미지 너비

height 이미지 높이

 

멀티미디어 태그

<audio> 오디오 파일

<video> 비디오 파일

 

입력양식 태그

form 입력 폼

input 입력 창

textarea 입력 영역

select 선택 폼

 

공간 분할 태그

<div> block 형식으로 공간 분할

<span> inline 형식으로 공간 분할

 

시멘틱 구조 태그

<header> 헤더

<nav> 네비게이션

<aside> 사이드에 위치하는 공간

<section> 여러 중심 내용을 감싸는 공간

<article> 내용

<footer> 푸터

<address> 주소

 

실습문제1 - 자기소개 페이지 만들기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자기소개 페이지</title>
</head>
<body>
    <header>
        <h1>지유빈의 자기소개 페이지</h1>
    </header>
    <hr/>
    <main>
        <img src="intro.png" alt="자기소개사진">
        <section>
            <h2>기본 자기소개</h2>
            <p>안녕하세요. 저는 멋쟁이사자처럼 백엔드스쿨 10기생 박경서입니다.</p>
            <p>저는 백엔드에 대해 공부하고 혼자서도 웹 페이지를 만들어보고싶습니다.</p>
        </section>
        <hr/>
        <section>
            <h2>취미 및 관심사</h2>
            <p>저의 취미는 야구 직관입니다.</p>
            <p>요즘 관심은 모루인형 만들기입니다.</p>
        </section>
        <hr/>
        <blockquote>늦었다고 생각할 때가 진짜 늦었다</blockquote>
        <cite>박명수</cite>
    </main>
    <hr/>
    <footer>
        <p>연락처 및 주소</p>
        <address>
            <p>주소 - 경기도 수원시</p>
            <p>연락처 - 010-1111-2222</p>
        </address>
    </footer>
</body>
</html>

실습문제2 - 블로그 포스트 페이지 만들기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>블로그 페이지</title>
</head>
<body>
    <header>
        <h1>HTML의 기본</h1>
        <p><small>2024-03-27 박경서</small></p>
    </header>
    <hr/>
    <main>
        <img src="html.png" alt="html아이콘">
        <p>오늘은 <strong>html의 기본</strong>을 배워보았다.</p>
        <p><em>다양한 태그</em>를 이용해 실습도 해보았다.</p>
        <a href="https://www.tcpschool.com/html-tag-attrs/img-alt" target="_blank">실습의 기본</a>
    </main>
    <hr/>
    <section>
        <h4>댓글</h4>
        <ul>
            <li>재밌었겠내요</li>
            <li>저도 배워보고 싶어요</li>
            <li>다음엔 어떤 걸 배우나요?</li>
        </ul>
    </section>
</body>
</html>

실습문제3 - 제품 소개 페이지

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>제품 소개 페이지</title>
</head>
<body>
    <header>
        <h1>갤럭시 제품 소개</h1>
        <p>갤럭시는 한국 최고 기업 삼성에서 만들어진 최고의 스마트폰입니다.</p>
    </header>
    <hr/>
    <main>
        <img src="g1.jpg" alt="갤럭시사진1" width="400px">
        <img src="g2.jpg" alt="갤럭시사진1" width="400px">
        <ul>
            <li>예쁜 색감</li>
            <li>좋은 기능</li>
        </ul>
    </main>
    <hr/>
    <hr/>
    <section>
        <article>
            <h3>사용자1</h3>
            <p>너무 잘 쓰고있어요.</p>
        </article>
        <hr/>
        <article>
            <h3>사용자2</h3>
            <p>약간 버벅거려요.</p>
        </article>
        <hr/>
    </section>
    <footer>
        <p>제품 구매 페이지</p>
        <a href="https://search.naver.com/search.naver?ssc=tab.nx.all&where=nexearch&sm=tab_jum&query=%EA%B0%A4%EB%9F%AD%EC%8B%9C" target="_blank">구매 관련 홈페이지</a>
    </footer>
</body>
</html>
728x90

'Spring > TIL - 멋쟁이사자처럼' 카테고리의 다른 글

4월 11일 TIL : final  (0) 2024.05.03

+ Recent posts