Coder Social home page Coder Social logo

demo-mall's Introduction

RecoPick Demo Mall

RecoPick의 기능 검증 및 테스트에 사용할 가상의 RecoPick 고객 쇼핑몰

11번가 상품 검색

curl -X GET \
  http://apis.skplanetx.com/11st/v2/common/products \
  -H 'accept: application/json' \
  -H 'appkey: 83aeb0b1-94db-3372-9364-22a13e6b6df2' \
  -H 'cache-control: no-cache'
curl -X GET http://apis.skplanetx.com/11st/v2/common/products?searchKeyword=sports -H 'accept: application/json' -H 'appkey: 83aeb0b1-94db-3372-9364-22a13e6b6df2' -H 'cache-control: no-cache'
curl -X GET http://apis.skplanetx.com/11st/v2/common/products/512242346 -H 'accept: application/json' -H 'appkey: 83aeb0b1-94db-3372-9364-22a13e6b6df2' -H 'cache-control: no-cache'

demo-mall's People

Contributors

homoefficio avatar

Watchers

James Cloos avatar  avatar  avatar

demo-mall's Issues

객체 사용 질문 입니다.

controller

    @GetMapping("/main/{userName}")
    public ModelAndView signIn(@PathVariable("userName") String userName, HttpSession session, ModelAndView mv) {
        mv.setViewName("main");
        session.setAttribute("userName", userName);
        setUserInfo(userName, mv);
        return mv;  // main 화면에서 memberId로 장바구니 조회해서 있으면 표시하도록
    }

main.ftl

<form id="myForm2" v-on:submit.prevent="sendPost()">
userNmae : {{ userName}}
    <input type="text" name="userName" v-model="userName"><br>
    <textarea name="birthYear" v-model="birthYear"></textarea><br>
    <input type="submit" value="Search" class="btn">
</form>

<script>
    new Vue({
        el: '#myForm2',
        data: {
            userName: '${Session.userName}',
            birthYear: '1990'
        }  ,
        methods: {
                sendPost() {
                    axios.post('/posttest/', {
                        userName: this.userName,
                        birthYear: this.birthYear
                    }).then(res => {
                                console.log(res);
                            })
                            .catch(err => {
                                console.log(err);
                            });
                },
            }
        });
</script>
  • 프리마커 문법인 ${} 내장객체를 사용하여 프리마커 파일안에 아래와 같이 작성해보았습니다.
  • userName 같은 경우 , 초기 값을 controller로 부터 가져온 값으로 설정 하고 싶어서 이렇게 작성 해 보았습니다.
  • 실제 사용된 예제 에서는 userName: 'hs' 같은 형대로 , staic하게 고정 되어있었는데요
  • 프리마커 안에 script를 함께 사용 하면 위와 같이 사용 할수 있는데

1. 예제처럼 js를 따로 분리하는 경우는 어떻게 사용해야 하나요?

2. 지금의 접근 방식이 잘못된 건가요?

form 태그 사용 이유 질문입니다.

index.ftl

<form class="pure-form">
   <input v-model="userName" placeholder="UserName을 입력하세요." autofocus>
   <input v-model="birthYear" placeholder="출생년도를 입력하세요. - yyyy">
   <input v-model="gender" placeholder="성별을 입력하세요. - M 또는 F">
    <button class="pure-button pure-button-primary" @click.prevent="onSignUp()">Sign Up</button>
</form>

이렇게 form태그로 지정해 주어서 사용 하였는데 ,

index.js

   axios.post('/members/', {
                userName: this.userName,
                birthYear: this.birthYear,
                gender: this.gender
      })

함수를 보면 , 데이터 전달을 각각 합니다.
실질 적으로

<form class="pure-form"> 부분을 <div > 이런식으로 던지 지정해주어도 같은 결과인데
form 으로 지정 한것은

1. form 태그로 지정된 부분은 나중에 전달이 된다는것을 명시하기 위해서 인가요?

2.1 $("#form").submit() , 같은 방법으로 전송은 안되나요?

2.2 $("#form").serialize() , 같은 방법으로 전송은 안되나요?

[vue] 메뉴 템플릿 구성 컴포넌트 질문입니다.

템플릿 버전 1

오차장님 예제에 따른 구성

  • main.ftl
<#include "/header.ftl">

<div id="app">
    
</div>

<script src="/js/main.js"></script>

<#include "/footer.ftl">

템플릿 버전2로 한 이유

  • vue에서 el : app 안에 포함되어야 사용할수 있어서

위의 main.ftl에서 <div id="app"><#include "/header.ftl"> 밖에 있어서
아래에 있는 header 컴포넌트구성으로는 쓸수 가 없었습니다.
그래서 템플릿 버전 2로 구현하였습니다.

공통

header 컴포넌트

Vue.component('apex-menu-bar', {
    template: `

<div class="pure-menu pure-menu-horizontal">
        
    </div>

    `
});

projectList.js

new Vue({
    el: '#app'
})
;

템플릿 버전2

소스

  • header.ftl
    <!-- vue.js -->
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="/js/component/apex-menu-bar.js"></script>
    <script src="/js/component/apex-footer.js"></script>
</head>
<body>
<div id="app">
<apex-menu-bar></apex-menu-bar>
  • main.ftl
<#include "/header.ftl">

<div class="main">
</div>
  
<apex-footer></apex-footer>
</div> <#--header에 있는 app 닫기 -->
<script src="/js/component/component-search.js"></script>
<script src="/js/project/projectList.js"></script> <#-- main.ftl 연관vue js></#-->
</body>

</html>

실행 에러 없음

문제

  1. 템플릿 버전 1의 예제처럼 app 밖에 위치 하지 않음
  2. footer.ftl 분리 되지 않음

템플릿 버전3

문제 2번 ( 템플릿 버전2의 footer.ftl 분리시 발생)

소스

  • footer.ftl
<apex-footer></apex-footer>
</div>
</body>

</html>
  • main.ftl
<#include "/header.ftl">

<div class="main">
</div>
  
<script src="/js/component/component-search.js"></script>
<script src="/js/project/projectList.js"></script> <#-- main.ftl 연관vue js></#-->


<#include "/footer.ftl">

에러내용

default

1.오차장님 예시 처럼 하려면, 어떻게 해야하나요?

컴포넌트를 지금처럼 사용하는 방법 말고 , 할수 있는방법이 있나요?

2.템플릿 3번처럼 분리하려면 , 구성을 어떻게 해야 하나요 ?

form submit 관련 질문 입니다

예제에서 사용된 submit 부분

1번

<form class="searchbar" v-on:submit.prevent="onSearch('${mid}', '${birthYear}', '${gender}')">
  <input v-model="newSearch" placeholder="Search for posters" autofocus>
  <input type="submit" value="Search" class="btn">
</form>

2번

<form class="pure-form">
   <input v-model="userName" placeholder="UserName을 입력하세요." autofocus>
   <input v-model="birthYear" placeholder="출생년도를 입력하세요. - yyyy">
   <input v-model="gender" placeholder="성별을 입력하세요. - M 또는 F">
    <button class="pure-button pure-button-primary" @click.prevent="onSignUp()">Sign Up</button>
</form>

두가지 방법으로 사용 되고 있는데 ,

  • 1번의 경우 submit이벤트 핸들러로 , onSearch라는 메소드가 호출이 되고
  • 2번의 경우 버튼클릭시 ,onSignUp 라는 메소드가 호출이 된다고 이해가 됩니다.

js 부분

1번

onSearch(mid, birthYear, gender) {
            if (this.newSearch.length) {
                this.items = [];
                this.loading = true;
                window.recoPick('sendLog', 'search', this.newSearch);
                axios.get('/api/search/'.concat(this.newSearch))
                    .then(res => {
                        this.lastSearch = this.newSearch;
                        this.results = res.data;
                        this.appendItems();
                        this.loading = false;
                    })
                    .catch(err => {
                        console.log(err);
                    });
            }
        }

2번

onSignUp(endPoint) {
            console.log('onSignUp');
            // POST /members/{memberName}
            axios.post('/members/', {
                userName: this.userName,
                birthYear: this.birthYear,
                gender: this.gender
            })
                .then(res => {
                    console.log(res);
                    this.onSignIn();
                })
                .catch(err => {
                    console.log(err);
                });
        },
    }
  • 두가지 방법의 경우 , 메소드 안에서 ajax post 형식으로 데이터가 전달이 되는데
    제 생각으로는 두가지 방법이 같게 느껴집니다.

1. 1번의 경우는 submit전에 호출되는 메소드니까 , submit 전에서 커스텀하게 사용하고 ,submit 할수 있다는 의미의 예제 인 건가요 ?

2. 두가지 방법을 사용하신 이유와 , 차이가 있나요?

[JPA] @Column 'columnDefinition' 속성 질문입니다

 @Column(name = "USER_KIND",columnDefinition = "varchar(45) default 'company'")
    private String userKind;

칼럼에 기본값 설정을 하는 방법을 찾아보니 columnDefinition 사용하라고 하여서
위와 같이 작성을 하였지만 , 적용되지 않습니다.
결과 값을 확인하니 , null로 들어가 있습니다.

기본값을 설정 하려면 어떻게 해야하는지 궁금합니다.


아래와 같은 방법으로도 초기값 설정이 가능 한데 ,

어색하지 않은 방법 인가요?

  @Column(name = "USER_KIND")
    private String userKind="company";
public Member() {
        this.userKind = "company";
    }

#8 연장 질문 입니다

#8 말씀하신 props는

1 ) main.js 
     addCart 메소드 호출  -> this.addedItem = this.items[index];
2)  component-cart.js 
    addedItem(main.js선언) 변화 감지  ->   this.addToCart(addedItem);
    watch: {
        addedItem(addedItem) {
            this.addToCart(addedItem);
        }
    }

이렇게 이해가 됩니다.

제가 지금 하려는 부분은 ,component.js에서 받은 값을 프로젝트.js로 넘기려고 합니다.이것도 props로 사용하면 된다는 말씀인가요.?

(컴포넌트에서 넣은 데이터객체인 result를 프로젝트리스트.js의 projectResults에 어떻게 데이터를 전달해야 할지 모르겠습니다.)

이렇게 컴포넌트를 구현하려는 이유는
아래의 3가지 결과화면 에서 , 가져오는 데이터 값은 같고 , 화면에서 버튼 종류가 다르기 때문에
검색 이라는 컴포넌트를 따로 빼서, 검색 컴포넌트를 통해서 초기 값 세팅과 , 검색 결과값 세팅을 공통으로 해주고
버튼을 설정하는 다른 버튼 부분은 프리마커로 하려 합니다.

결과 화면

image

image

image

검색 컴포넌트

>>> 검색 탬플릿
image

Vue.component('project-search', {
    template: `
           >>> 검색 탬플릿
    `,
    data() {
        return {
         results: {}
        };
    },
    methods: {
        onSearch() {
          >>> this.results  = 검색 결과 데이터 가져오기
        }
    },
    created() {
      >>>  this.results = 초기 전체 데이터 가져오기 
});

프로젝트리스트 .js

new Vue({
    el: '#app',
    data: {
        projectResults: {},
    }

프로젝트리스트 .프리마커

<h1 class="link">프로젝트 리스트</h1>
 <project-search  ></project-search>

   <div class="product" v-for="(item, index) in projectResults">
 <p>작업 위치: {{ item.project.projectPlaceAddress }}</p>
   <div v-if="item.authorityCode == '02'">
   <button class="btn add-to-cart" @click="modifyProject(item.project.projectCode)">수정</button>                    
    </div>

이런경우 컴포넌트로 빼는것이 아닌 것인가요 .?

이런 경우에도 props를 이용하는 것이 맞나요?

[vue.js] componet 질문입니다

search-componet.js

Vue.component('project-search', {
    template: `
             <form class="searchbar" v-on:submit.prevent="onSearch()">
            <select v-model="searchType" >
                <option value="name">프로젝트 이름</option>
                <option value="manager">프로젝트 매니저</option>
            </select>
            <input v-model="newSearch" placeholder="Search for posters" autofocus>
            <input type="submit" value="Search" class="btn">
        </form>  
    `,
    data() {
        return {
            projectView: '/project',
            memberView: '/member',
            userId: '',
            uid: window.demoUserUid,
            total: 0,
            items: {},
            searchType:'',
            results: {},
            newSearch: '',
            lastSearch: '',
            loading: false,
        };
    },
    methods: {
        onSearch() {
            if (this.newSearch.length) {

                this.items = [];
                this.loading = true;
                axios.get(this.memberView+'/search/'.concat(this.searchType).concat('/').concat(this.newSearch))
                    .then(res => {
                        this.lastSearch = this.newSearch;
                        this.results = res.data;
                        this.loading = false;
                        addedItem=this.results;
                    })
                    .catch(err => {
                        console.log(err);
                    });
            }
        }
    }
});

created() 실행 결과

image
image

projectList.js


new Vue({
    el: '#app',
    data: {
        addedItem:{}

    }

projectList.ftl

    <project-search ></project-search>
   <div class="product" v-for="(item, index) in addedItem">
<div>
           <p>작업 위치: {{ item.project.projectPlaceAddress }}</p>
            <div v-if="item.authorityCode == '02'">
          <button class="btn add-to-cart" @click="modifyProject(item.project.projectCode)">수정</button>
 </div>

 

project-search에서의 results의 값을 'projectList.js'에서 addedItem에 전달해서 사용하고 싶은데 , 어떻게 연동해야 하나요?

addedItem=this.results; 우선 이런식으로 하려했는데 데이터가 들어가지 않는데 ,
자식 -부모 관계 이런게 나오는데 , 이런경우는 자식이 부모에게 데이터 전달인건가요 ?

[JPA]

1번 JPQL코드

@Repository
public interface ProjectRepository extends JpaRepository<Project,Integer> {
 @Query("select a.project, count(a.memberCode) as memberNum " +
            "from Member1 a " +
            "where a.project.projectFlag = :projectFlag " +
            "group by a.project")
    Page<Project> findProjectAndMember(@Param("projectFlag") String projectFlag, Pageable pageable);

2번 실행결과

image

3번 Native Query

@Query(value = "select user_id, user_name from users ", nativeQuery = true)
List<Object[]> findUSBCandidates();
◾ Native Query는 Repository에서 @Query(value=“쿼리문”, nativeQuery = true)로 수행한다.
◾ 컬럼이 하나 혹은 엔티티 객체일 경우에는 리턴값을 해당 타입 혹은 해당 타입의 리스트로 지정한다.
◾ 다중 컬럼일 경우에는 Object []로 받아서 컬럼 지정 순서대로 값을 뽑아서 사용한다.

프로젝트의 맴버 수를 구해서 memberNum에 넣고 싶어서 , 1번 방식으로 jpql을 적용하였습니다.
그런데 2번의 결과를 보니 , Project객체로 넘겨주었음에도 불구하고 , 배열로 전달이 된것을 확인 하였습니다. 그래서 찾아보니 3번 다중 컬럼일 경우에는 Object []로 받아서 컬럼 지정 순서대로 값을 뽑아서 사용한다. 라고 합니다.

이런 경우에 2번의 노란색으로 체크된 object[1]번의 값을 , object[0]의 memberNum에 넣어서 하나의 객체로 받을 수 있는 방법이 있을까요?

없다면 , 이렇게 사용하는 것이 맞나요?

[JPA] update 질문입니다

SQL문

		UPDATE
		project SET
		projectFlag='0',userId=#{userId}
		WHERE
		projectCode=#{projectCode}

일때 , update하고 싶은 값만 변경 할수 있는데요

JPA

 public void delete(int projectCode) {
        Project project = projectRepository.findOne(projectCode);

        project.setProjectFlag("0");
       project.getUser().setUserId("gcssystem");  

        projectRepository.save(project);
    }

find를 통해서 project객체를 받은 다음에 , 거기서 update하고 싶은 값을 변경해서 save 하는 방법을 사용해야 하는것 인가요?

2번의 과정을 거져야 하는 것인가요? 위의 방법 말고 다른 방법도 있나요?

[JPA] 트랜잭션 범위의 영속성 컨텍스트 질문 입니다.

#6 의 연장 질문 입니다

@Transactional
public class ProjectService {
public void delete(int projectCode) {
     
        Project project = projectRepository.findOne(projectCode);
        project.setProjectFlag("0");
        
    }
}

update를 다시 하지 않아도 되는 이유가

1. @Transactional  선언해서 트랜잭션 시작 
2. project는 영속 상태 
    projectRepository.findOne(projectCode) 통해 조회한 project엔티티는
   트랜잭션 범위 안에 있으므로 ,영속성 컨텍스트의 관리를 받는다
3. project는 영속 상태로 변경 감지가 가능한다
4. @Transactional 선언한 메소드가 정상 종료 되면 
   1. 트랜잭션 커밋 = 영속성 컨텍스트 종료 = 엔티티 매니저 플러시가 호출
   2. 스냅샷으로 변경된 엔티티 찾는다
   3. 변경된 엔티티가 있으면  수정 쿼리를 생성해서 , 쓰기 지연 sql 저장소에 보낸다
   4. 쓰기 지연 저장소의 sql을 데이터 베이스에 보낸다
   5. 데이터베이스의 트랜잭션을 커밋한다

위의 내용으로 이해가 됩니다.
찾아보니 트랜잭션 범위와 영속성 컨텍스트의 생존 범위가 같고

같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다

라고 하는데

같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다 에 관해서

클래스 단에 @Transactional 으로 설정 한경우 질문입니다.

각각의 메소드가 각각의 트랜잭션을 시작하고 , 각각의 메소드에서 컨텍스트 생존범위가 존재하는 걸로 이야하면 될까요 ?

(=메소드 마다 다른 트랜잭션이 생기고 , 영속성 컨텍스트가 메소드 마다 다르게 생기는 것이 맞나요?)

post 전송 관련

post로 데이터를 전송한 후 Controller에서 받을 때, 아래 두 가지가 다른 형태로 받아집니다.

  1. form에 데이터를 입력받아 삽입한 경우, Controller에서 객체로 받을 수 있음.
  • Vue.js
    onPrjSave() {
                console.log();
                // POST /projects
                axios.post('/project/projects/', {
                    projectCode: this.project.projectCode,
                    projectName: this.projectName,
                    projectDetail: this.projectDetail,
                    projectBeginDate: this.projectBeginDate,
                    projectEndDate: this.projectEndDate,
                    projectDesignCo: this.projectDesignCo,
                    projectConstructionCo: this.projectConstructionCo,
                    projectOrderCo: this.projectOrderCo,
                    projectWorkCompletedDate: this.projectWorkCompletedDate,
                    projectWorkStartsDate: this.projectWorkStartsDate,
                    projectPlaceAddress: this.projectPlaceAddress,
                    projectPlaceAddressDetail: this.projectPlaceAddressDetail,
                    projectManager: this.project.projectManager
                })
                    .then(res => {
                        console.log(res);
                        alert("저장 성공!");
                    })
                    .catch(err => {
                        console.log(err);
                    });
  • Controller
    @PostMapping("/projects")
        @ResponseBody
        public void insUpdProject(@RequestBody Project project, HttpSession session) {
            Objects.requireNonNull(project, "Project is null");
           ..
        }
  1. 그냥 전송한 경우, Cotroller에서 @RequestParam으로 받을수 없습니다. 확인한 결과, 데이터가 json형태로 넘어와 Map<String, String> 으로 받을 수 있었습니다.
  • Vue.js
    axios.post('/project/search/workTerm', {
                        startDate: this.startDate,
                        endDate: this.endDate
                    })
  • Controller
    @PostMapping("/search/workTerm")
        @ResponseBody
        public ResponseEntity<List<Project>> searchWorkTermlist(@RequestBody Map<String, Date> date,
                                                                @RequestParam(defaultValue = "0", required = false) int page,
                                                                HttpSession session) {
    
            return ResponseEntity.ok(projectService.getProjectWorkTermSearchList(date.get("startDate"), date.get("endDate"), page));
        }

**Q1. 입력받아 넘긴 데이터 라는 것 외에는 1번과 2번이 다른 부분이 없는데. 1번에선 객체로 받고, 2번에서는 Map 으로 받아야 하는 이유가 뭔가요?

Q2. 2번에서 Map<> 말고 객체 혹은 여러 파라미터로 받는 방법이 있다면, 어떻게 해야하나요?**

Domain/DTO/VO & Repository 구분 및 정의

Domain

  • 테이블과 1:1 매핑됨
  • 테이블을 표현한 객체

DTO

  • 파라미터 객체

VO

  • Value Object의 약자로, Value만 담고 있는 객체

Repository

  • CRUD 기능을 가지고 있고, CRUD 결과를 반환해줌

쇼핑몰 예제를 보며, 사용된 개념들을 위와 같이 이해했습니다.

궁금증

Q1. 각각의 개념과 역할을 위와 같이 이해하고 예제를 접근하는게 맞나요? 그렇지 않다면, 어떤 역할로 사용하셨나요?
Q2. DTO와 Domain의 차이가 미묘하게 느껴집니다. DTO 없이 Domain만 사용한다면 어떤 문제점/불편함이 발생할 수 있나요?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.