스프링 오랜만에 다시 보내 새롭네요. 우연히 접할 기회가 있어서 스프링 부트를 접하게 되었습니다. 기존에 주로 회사에서는 php, ruby on rails, javascript 등 스크립트 언어를 해오다 보니 꽤나 쉽지 않네요. 뭐 이걸로 프로젝트를 한 번 하면 금방 배우겠죠. 루비 같은 경우도 작년까지 전혀 몰랐는데, 프로젝트를 하다보니 점점 알게 되더라구요. 

1. 셋팅

이걸 하면서 gradle이라는 것을 알게 되었는데, 보니까 maven 같은 것인데, 확실히 maven보단 설정 문법이 더욱 깔끔하고 좋네요. maven에서는 xml 지옥이라 알아보기 힘들었는데, gradle은 그냥 스크립트 형식으로 되어있어서 더 알아보기 쉽게 되어있습니다. 

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.10.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'spring-boot'

sourceCompatibility = 1.5
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    compile("org.springframework.boot:spring-boot-starter-web:1.2.0.RELEASE")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("mysql:mysql-connector-java:5.1.34")
}

맨 위에 buildscript부분은 jar파일 만들기 위해서 필요한 것 같아요. 그 외에 plugin이 spring-boot가 추가되었는데, bootRun 이런 task 등이 추가 되어있어요.

dependencies는 스프링 부트를 쓰려면 spring-boot-starter-web이 있어야 하고, 데이터연동하는 것을 하기 위해서는 spring-boot-starter-data-jpa가 있어야 하고, mysql을 쓰려면 mysql-connector-java를 추가해야 해요.
jpa에는 하이버네이트가 내장되어 있어요.


2. 메인 클래스

스프링 부트는 예전 개발방식이랑 틀리게 톰캣 받고, web.xml을 셋팅하고, 웹개발을 위한 셋팅이 필요없이 기존 java 실행 방식으로 실행하며 이 실행과 동시에 내장된 톰캣이 작동하여 서버를 만들어버립니다. 아래와 같이 메인클래스를 만들어버리면 그냥 웹서버애플리케이션이 뜹니다.

Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

    }
}

보면 예전에 자바처음 배울 때 쓰는 public static void main클래스로 실행만 합니다. @SpringBootApplication어노테이션을 붙이면 최초 기본셋팅으로 톰캣을 띄워서 8080포트로 서버를 만들어 줍니다.


3. 모델 생성

그 전에 접속할 db정보를 입력해야 합니다. 
application.properties

spring.datasource.url=jdbc:mysql://127.0.0.1/sosi?autoReconnect=true&useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database=mysql
spring.jpa.show-sql=true

대략 설정값은 저런데 ddl-auto부분이 create-drop은 서버 재시작 때마다 테이블을 날려버리는 옵션입니다. 처음에 개발할 때에는 매우 편리합니다. 값을 매번 지우지 않고도 서버만 재시작해도 처음부터 다시 개발 해놓은 것을 테스트해볼 수 있으니깐염.

Sosi.java

@Entity public class Sosi { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(nullable = false) private String name; @OneToMany @JoinColumn(name="sosi_id", referencedColumnName="id") private List<Schedule> scheduleList; public Sosi() { } public Sosi(String name) { this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Schedule> getScheduleList() { return scheduleList; } public void setScheduleList(List<Schedule> scheduleList) { this.scheduleList = scheduleList; } }


Schedule.java

@Entity
public class Schedule {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    @JsonBackReference
    private Sosi sosi;

    @Column
    private String program;

    public Schedule() {
    }

    public Schedule(Sosi sosi, String program) {
        this.sosi = sosi;
        this.program = program;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Sosi getSosi() {
        return sosi;
    }

    public void setSosi(Sosi sosi) {
        this.sosi = sosi;
    }

    public String getProgram() {
        return program;
    }

    public void setProgram(String program) {
        this.program = program;
    }

}

두 개의 모델이 1:N관계 입니다. Sosi가 스케줄을 여러개 가질 수 있는 구조입니다. 여기서 Schedule에는 ManyToOne을 걸었는데, @JsonBackReference도 같이 넣었습니다. 이걸 안 넣으면 서로 계속 참조해서 JSON출력할 때 무한루프에 빠지더라구요-_- 이제 Sosi참조는 json에서 안쓰는 그런 옵션 같습니다.

그리고 예전에는 Dao만들어서 뭔가 하이버네이트세션 가져와서 그걸 통해서 했던 것 같은데, Spring Data JPA에서는 JpaRepository라는 것을 제공하는데, 이것을 통하면 해당 모델에 대해서 CRUD를 제공합니다. 

SosiRepository.java

public interface SosiRepository extends JpaRepository<Sosi, Long>{
}

ScheduleRepository.java

public interface ScheduleRepository extends JpaRepository<Schedule, Long> {
}


4. 컨트롤러 생성

간단하게 소녀시대 정보를 가져오는 컨트롤러와 스케줄 추가 및 가져오는 컨트롤러를 생성합니다.

SosiController.java

@RestController
@RequestMapping("/sosi")
public class SosiController {

    @Autowired
    private SosiRepository sosiRepository;

    @RequestMapping("{sosiId}")
    public Sosi getSosi(@PathVariable Long sosiId) {
        Sosi sosi = sosiRepository.findOne(sosiId);
        return sosi;
    }
}

ScheduleController.java

@RestController
@RequestMapping("/schedule")
public class ScheduleController {

    @Autowired
    private ScheduleRepository scheduleRepository;

    @Autowired
    private SosiRepository sosiRepository;

    @RequestMapping("{scheduleId}")
    public Schedule getSchedule(@PathVariable Long scheduleId) {
        Schedule schedule = scheduleRepository.findOne(scheduleId);
        Sosi sosi = schedule.getSosi();
        return schedule;
    }

    @RequestMapping("add/{sosiId}")
    public Schedule addSchedule(@PathVariable Long sosiId, @RequestParam(value="program") String program) {
        Sosi sosi = sosiRepository.findOne(sosiId);
        Schedule schedule = scheduleRepository.save(new Schedule(sosi, program));

        return schedule;
    }
}

소스 내용을 보면 Repository클래스를 통해 Autowired하면 기본 인터페이스를 해당 모델기반 구현체를 만듭니다. 그 구현체에서 save, findOne 등 함수를 통해 데이터 삽입 및 가져올 수 있습니다.


5. 기본 값 삽입

기본적으로 소녀시대 멤버를 삽입하고 시작할 수 있습니다. 기존 application.properties에 하이버네이트 설정을 재시작하면 꺼지게 해놨기 때문에 기본적으로 앱을 시작할 때 값을 삽입하고 하면 편하게 테스트할 수 있습니다.

Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        SosiRepository sosiRepository = context.getBean(SosiRepository.class);

        sosiRepository.save(new Sosi("태연"));
        sosiRepository.save(new Sosi("윤아"));
        sosiRepository.save(new Sosi("수영"));
        sosiRepository.save(new Sosi("효연"));
        sosiRepository.save(new Sosi("유리"));
        sosiRepository.save(new Sosi("티파니"));
        sosiRepository.save(new Sosi("써니"));
        sosiRepository.save(new Sosi("서현"));
    }
}


6. 실행

소녀시대 정보 가져오기
http://localhost:8080/sosi/1

스케줄 추가하기
http://localhost:8080/schedule/add/1?program=무한도전

다시 소녀시대정보 가져오기
http://localhost:8080/sosi/1


예제 소스는 깃헙에...
https://github.com/mudchobo/sosi-schedule-sb

 
Posted by 머드초보
,
 

리듬 게임을 참 좋아했는데요. 중학교 때 비트매니아 보고 반해서 그때부터 좋아하기 시작해서 아직까지 즐기고 있네요. 그 당시 비트매니아는 300원이였는데, 부평에 가야지만 있어서 버스타고 가서 했던 기억이 나네요. 너무 비싸서 집에 컴퓨터용 비트매니아 프로그램으로 연습해서 오락실에서 하고 그랬던 기억이 나네요. 

이제 스마트폰이 보급화 되면서 스마트폰에서도 리듬게임이 한창 인기가 있었는데, 그 1세대가 탭소닉이였던 것 같습니다. 탭소닉은 스마트폰에 맞게 터치앤드래그 형식으로 리듬게임을 즐기는 방식입니다. 이것도 한창 인기가 있었는데, 어느새 시들해졌네요. 그러고 나서 많은 리듬게임이 나왔는데, 탭소닉 링스타 for Kakao, DJMAX 태크니카 for Kakao 등 다양한 리듬게임이 나왔어요.

탭소닉 링스타는 예전 NDS시절 리듬히어로 방식처럼 큰 원이 점점 작아지면서 터치할 원에 일치할 때 터치하는 방식의 리듬게임입니다. 그리고 DJMAX는 노트들이 나타나고 그 노트들을 선이 지나갈 때 터치하는 리듬게임이죠. 이렇게 다양한 리듬게임이 나왔는데, 대부분 성공하지 못했어요.

그래서 최근에 나온 것이 SuperStar SMTOWN인데, 이게 어느정도 중박을 친 게 아이돌과 리듬 게임의 조합입니다. 그래서 아이돌 팬들이 이 게임에서 자신이 원하는 아이돌의 카드를 모으기 위해서 게임을 할 수 있습니다. 이런 방식이 어느 정도 먹힌 것이죠. 


1. 전체적으로 깔끔한 외쿡 스타일 디자인

로고화면

위의 로고 화면처럼 전체적으로 외쿡스타일의 게임형태로 되어 있습니다. 실제로도 이 게임은 외국 사람들도 꽤 많이 하고 있죠. 물론 디자인 때문이 아니라 외국에 팬을 많이 보유하고 있는 SM가수의 영향이 가장 크죠.

랭킹 화면입니다. 화면의 아이콘도 매우 심플하게 설명없이 배치되어 있네요. 

(1) 상단 메뉴

헤드폰 - 게임을 플레이할 수 있는 수 인데(애니팡의 하트같은...), 지금 52개 있는데, 나중에 다 쓰면 5분마다 한 개씩 차며 맥스 5개입니다. 

R(리듬포인트) - 곡을 클리어 하면 주는 포인트인데, 이걸 모아서 일반 카드를 뽑거나 카드를 강화에 사용합니다. 

다이아몬드 - 현질하거나 주간 랭킹에 순위권에 들면 얻을 수 있는 돈 같은 존재입니다. 프리미엄 카드(B~S등급)를 뽑을 수 있고, 헤드폰을 구매하거나 R을 살 수 있습니다.

(2) 하단 메뉴

카드 - 내가 보유하고 있는 카드 덱을 보여줍니다. 여기에 SM가수별로 나열되어 보여집니다. BoA(보아), TVXQ!(동방신기), Super Junior(슈퍼주니어), KyuHyun(규현), Super Junior-M(슈퍼주니어엠), Henry(헨리), ZhouMi(조미), Girls'Generation(소녀시대), Girls'Generation-TTS(태티서), SHINee(샤이니), TAEMIN(태민), f(x)(함수), EXO-K(엑소케이), EXO-M(엑소엠), RedVelvet(레드밸벳), SMTOWN으로 나눠져 있습니다. 카드를 장착하면 그 곡을 클리어 시 더 높은 점수를 얻을 수 있습니다. 카드 시스템은 아래에 다시 한 번 더...

상점 - 다이아몬드, R(리듬포인트), 헤드폰, 카드팩, 인벤토리확장 등을 구매할 수 있는 페이지입니다.

우편함 - 운영자가 보상을 주거나, 주간랭킹 보상 등은 다 이곳을 통해서 받습니다.

도움말 - 게임에 필요한 도움말입니다.


2. 곡 목록 화면

처음에 곡이 다 잠겨있는데, 계속 클리어해야 다음 곡이 열립니다. 한 100여곡 되는 것 같았어요. 최초 미션 클리어 시에는 C급 카드도 한장씩 줍니다. 클리어 시에 주는 줄 알았는데, 그게 아니더라구요. 전부 다 깨면 그때부터는 리듬포인트 모아서 카드팩을 구매하셔야 합니다.

그리고 가끔 챌린지가 뜨는데, 이게 언제 뜨는지 모르겠는데, 지 꿀리는 대로 뜨는 것 같더라구요-_- 자신의 점수 그 이상을 받으면 C급카드랑 리듬포인트10배수치(약 5000~6000정도 주는 것 같음)을 줍니다. 챌린지가 뜨면 약 3번의 기회가 주어지는데, 3번안에 못깨면 챌린지모드는 사라집니다. 다시 개 노가다...


3. 게임 화면

아이폰6가 깔끔하게 동영상 캡쳐가 되어서 게임 화면은 잘 찍어놨습니다. 으핫. 유튜브에서 노래는 저작권에 위반되어서 삭제했습니다ㅠ
게임은 탭소닉과 동일한 형태입니다. 롱노트와 터치노트 두가지 방식으로 구성되어있는데, 약간 다른 점이라면 터치포인트가 정확하게 없다는 것입니다. 그냥 내려오는 것에 맞춰서 터치해야 합니다.
그리고 생명 게이지가 떨어지면 사망합니다. 생명게이지에서 안 틀리고 더 잘하면 게이지가 하나 더 차는데, 그때부터 점수보너스가 더 주는 것 같더라구요. 


4. 카드 시스템

카드시스템은 최근 유행하는 카드 시스템과 매우 많이 닮았습니다. 카드를 강화하거나 카드를 진화(여기에선 업그레이드)하는 시스템이 있습니다.

(1)가수별 덱

가수별로 카드를 장착하는 슬롯이 정해져있습니다. 보아를 보면 카드에 VOCAL, DANCE, RHYTHM 슬롯이 있으며, 여기에 장착을 하게 됩니다. 

카드 슬롯을 선택하면 또 해당 카드를 장착할 수 있는 카드가 있습니다. 여기선 해당가수-슬롯위치만 장착할 수 있습니다. 마치 무기아이템이 무기슬롯에만 장착이 가능한 것 처럼요. 그래서 리듬슬롯을 누르면 리듬슬롯 카드만 아래에 나와서 선택하면 비교화면이 나와서 장착할 것인지 묻습니다.

(2)카드 파워업

카드가 처음에 파워업을 하지 않으면 1성부터 시작하는데, 여기서 같은 종류의 가수 카드를 통해서 파워업을 할 수 있습니다. 파워업을 할 때에는 실패를 하면 그냥 카드가 사라져버립니다. 몬스터 길들이기처럼 강화포인트 개념이 없어서 그냥 생카드만 날라갑니다-_-(이것때문에 좀 빡치는...). 

C등급 카드로 C등급 카드를 강화하면 Power Up 성공률이 High인 반면에, C등급 카드로 S등급 카드를 강화하면 Power Up 성공률이 Low가 나옵니다. 등급에 가까울수록 강화확율이 높습니다.
S등급 카드에 B를 넣으니 Normal이네요.

 성공을 하면 별이 하나씩 붙습니다. 4번성공하면 5개의 별이 붙어서 더 이상 파워업을 할 수 없게 됩니다. 그 뒤로는 Power Up버튼이 Upgrade버튼이 바뀝니다. 

(3) 카드 업그레이드

카드 5성이 되면 그 다음부터 업그레이드를 할 수 있습니다. 업그레이드는 같은 등급의 5성카드 2개끼리 합치면 다음 등급으로 업그레이드를 할 수 있는 기능입니다. 그래서 상위등급으로 갈 수 있는 것이지요. 결국 생각해보면 노현질로 엄청난 곡클리어 노가다를 하게 되면 언젠가 전부 R로 덱을 도배할 수 있다는 것이지요. 그게 힘들다면...현질을 해야하는 뭐 다른 모바일게임과 전혀 다르지 않는 시스템입니다.


5. 총평

리듬게임 치고 꽤나 잘 만든 게임 같습니다. 다만 SM노래밖에 없다는 것이... 이게 장점이 될 수도 단점이 될 수도 있겠네요. 리듬게임에 아이돌카드를 접목한 것은 꽤나 잘 한 것 같습니다.

 
Posted by 머드초보
,
 
회사메일이 뭔가 맥용 메일 클라이언트랑 호환이 잘 안되는지 메일 푸쉬가 잘 안되어서 크롬플러그인으로 만들었습니다. 지메일용 unread 체크 표시해주는 플러그인이 있어서 거기서 영감을 받아 만들었습니다. 이게 근데 Node.js용 서버가 있어야 합니다-_- 크롬 익스텐션에서 뭔가 소켓통신이 될 줄 알았는데, 잘 안되더라구요.

그래서 chorme-extension -> Node.js서버로 읽지 않은 메일이 있는지 확인 요청 -> Node.js가 imap서버에 연결하여 읽지 않은 메일을 가져오기 방식으로 구현했습니다. 그리고 Socket.io를 쓴 이유가 커넥션을 계속 맺고 있으려고 그렇게 했는데, 최초 imap서버에 로그인하는데 오래걸려서 이미 커넥션을 맺고 있으면 읽지않은 메일 가져오는 서치는 빠르게 되더라구요. 그래서 그렇게 했는데... 음… 만들다보니 이게 최선이였…..

Node.js에서는 Socket.io를 이용해 크롬 익스텐션과 통신을 합니다.
imap서버를 지원하는 다음메일, 네이트메일, 네이버메일은 잘 되네요. 지메일도 잘 되는데, 신뢰하지 않은 애플리케이션 옵션을 꺼야지 되네요. 

1. Socket.io 프로토콜 구조

client -> server

login(id, pw, imap_server, imap_port, imap_tls)
로그인 요청. IMAP서버 연결정보를 전달해서 줌. 서버는 IMAP서버에 연결.

unseen()
읽지 않은 메일 아이디 목록 요청.

mail_info(mailId)
메일아이디로 메일정보 요청.

server -> client

connect()
클라이언트가 연결되면 전송.

login_success()
로그인 요청올 때 IMAP서버에 연결 후 이상이 없으면 전송.

unseen_result()
unseen요청이 올 때 unseen목록을 전송.

mail_info_result()
mail_info요청이 올 때 메일의 제목 및 보낸 사람 정보 전송.

server_error()
서버에서 IMAP서버에서 끊어지거나 예외 에러가 발생한 경우 전송.

대충 이렇습니다. 서버 에러가 나면 disconnect날려서 끊어버리면 클라가 다시 또 재연결을 시도합니다. 이런 식으로 좀비적으로 계속 붙어서 서버가 살아낼 때까지 연결합니다-_-
이제 실행법은 아래와 같습니다.


2. 로컬 서버 실행

서버 소스주소입니다.
RSA키키 만들고 실행하면 서버가 실행됩니다.
openssl genrsa -out rsa_1024_priv 1024
openssl ras -pubout -in rsa_1024_priv -out rsa_1024_pub
node app.js


3. 크롬확장프로그램 설치

크롬 확장프로그램 소스주소입니다.
위에서 만든 RSA키의 rsa_1024_pub키를 클론받은 소스 경로에 복사합니다.
크롬 실행 -> 설정 -> 확장프로그램 -> 개발자모드 체크 -> 압축해제된 확장프로그램 로드 후 소스 받은 경로 선택 하면 자동으로 설치가 됩니다.

4. 옵션 설정

오른쪽 상단에 표시된 크롬확장프로그램 아이콘에 오른쪽 버튼 클릭 후 옵션 선택하면 옵션이 나옵니다.

IMAP Server셋팅 대로 그대로 쓰시면 되고, 마지막 Enter WebMail Url은 크롬확장프로그램 클릭 시 이동하는 URL을 쓰면 됩니다.
저장 누르면 제대로 작동할 것입니다.

부록

Heroku서버에 올린 것과 연동된 플러그인을 크롬 웹스토어에 올렸습니다. 로컬서버 안 띄우고 제가 올린 서버와 연동되서 하는 것이긴 한데, 서버가 언제 죽을지는 모르니 참고하세요-_-

https://chrome.google.com/webstore/detail/imap-mail-checker/kbjiiglaopkgdnimdapohppnaeiocnbg?utm_source=chrome-ntp-icon

 
Posted by 머드초보
,
 

laravel설치법 나중에 찾아볼라고 기록 ㅇㅇ

brew

MAC에서는 brew라는 게 있는데, 없는 거 빼고 다 있는 만능 도구에요. 필요한 패키지는 검색해서 찾아서 설치하면 됩니다. apache, php, composer 등도 전부 brew로 설치할 수 있어요.

php framework Laravel

php프레임워크인데, ruby on rails스타일과 매우 흡사하고, 일반적인 MVC형태이며, DB마이그레이션도 제공하고, ORM같은 것도 제공하는 프레임워크에요.


1. apache설치

brew install httpd24

설치하면 가끔 brew tap어쩌구 나오는데, 그거 그냥 치고 하면 되는듯염. 


2. php56설치 및 필요 extension 설치

brew install php56
brew install php56-mcrypt


3. apache + php 연동

brew로 설치했다면 아파치설정파일이 /usr/local/etc/apache2/밑에 존재합니다. php랑 연동하려면 module을 추가해야 합니다.
추가로 rewrite.so도 추가해야합니다(이건 원래 있는건지 잘 모르겠지만 rewrite기능이 되야 합니다) 

httpd.conf

LoadModule rewrite_module libexec/mod_rewrite.so
LoadModule php5_module /usr/local/opt/php56/libexec/apache2/libphp5.so

<FilesMatch \.php$> 
    SetHandler application/x-httpd-php 
</FilesMatch>

그러고 apachectl restart 하면 재시작.


4. composer 설치

brew install composer


5. laravel 설치

http://laravel.com/docs/4.2/quick#installation
설치방법은 위에 사이트대로 두 가지 방법이 나와 있어요. 한 가지는 composer를 통해 laravel-installer를 설치해서 laravel 실행파일로 프로젝트를 앞으로 계속 생성하는 것이고, 다른 한 가지는 composer로 그냥 프로젝트를 만드는 방법이 나와있어요.
첫번째 laravel-installer 설치하는 게 뭔가 더 레일즈 스러워 첫번째 방법으로...

composer global require "laravel/installer=~1.1"

이거 할 때 혹시 메모리가 딸리다고 나오면, php의 메모리설정을 늘려주면 됩니다.
brew로 설치한 php가 기본이라면 /usr/local/etc/php/5.6/php.ini에 memory_limit=1G로 바꿔주고 하면 잘 됩니다. 설치할 때 뭔가 메모리를 겁나 먹는듯염.


6. laravel 프로젝트 만들기

laravel new blog

원하는 디렉토리에서 위와 같은 명령어를 치면 blog로 디렉토리를 만들어주면서 기본적으로 필요한 프로젝트를 만들어줍니다.


7. 해당 프로젝트와 아파치 virtualhost 연동

아파치에는 해당 프로젝트에 public디렉토리를 DocumentRoot로 잡으면 됩니다. 아파치 vhost파일을 수정해요. 그리고 기본적으로 httpd.conf파일에 Include /usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf부분에 주석처리 제거해야해요. 그러고 httpd-vhost.conf파일을 수정해봅시다.
/usr/local/etc/apache2/2.4/extra/httpd-vhosts.conf

<VirtualHost *:8080>
    DocumentRoot "/Volumes/d/laravel/blog/public"
    <Directory "/Volumes/d/laravel/blog/public">
        Options Indexes FollowSymLinks
        AllowOverride
        All Require all granted
        DirectoryIndex index.php
    </Directory>
    ServerName local.blog.com
    ErrorLog "/usr/local/var/log/apache2/blog.com-error_log"
    CustomLog "/usr/local/var/log/apache2/blog.com-access_log" common
</VirtualHost>

ServerName을 local.blog.com으로 들어오는 것에 대해서는 위와 같이 처리하도록 했습니다.
그럼 host를 잡고 테스트를 해봅시다. 
/etc/hosts 파일에 아래와 같이 추가해야 해당 서버로 인식합니다.

127.0.0.1   local.blog.com


8. 실행!

기본아파치 포트가 8080으로 되어있더라구요. 


우오오 잘됨 ㅇㅇ

 
Posted by 머드초보
,