Spring과 vue를 이용한 장소 목록 출력하기

이애옹·2022년 9월 20일
0
post-thumbnail

💬 내가 가지고 있는 '서울 장소' 데이터를 이용하여 목록을 출력했다 !!

사용할 테이블은 Seoul_natrue, Seoul_shop, Seoul_location
(세 테이블의 칼럼 구조는 똑같다 ^---^)
=> 똑같은 칼럼의 테이블을 여러개 사용하기 때문에, 코드를 효율적으로 쓰기 위해
하나의 코드로 세개의 테이블을 제어해보려고 한다!

해당 테이블의 칼럼 구조는 다음과 같다

이름 널? 유형


NO NOT NULL NUMBER
TITLE NOT NULL VARCHAR2(200)
POSTER NOT NULL VARCHAR2(500)
MSG NOT NULL VARCHAR2(4000)
ADDRESS NOT NULL VARCHAR2(300)
HIT NUMBER

📝 SeoulVO 생성하기

package com.sist.vo;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class SeoulVO {
	private int no,hit;
	private String title,poster,msg,address;
}

📝 SeoulMapper 생성하기

import java.util.*;

import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.sist.vo.*;
public interface SeoulMapper {
   @Select("SELECT no,poster,title,num "
		  +"FROM (SELECT no,poster,title,rownum as num "
		  +"FROM (SELECT no,poster,title "
		  +"FROM ${table_name} ORDER BY no ASC)) "
		  +"WHERE num BETWEEN #{start} AND #{end}")
   public List<SeoulVO> seoulListData(Map map);
   
   @Select("SELECT CEIL(COUNT(*)/12.0) FROM ${table_name}")
   public int seoulTotalPage(Map map);
   
   @Update("UPDATE ${table_name} SET "
		  +"hit=hit+1 "
		  +"WHERE no=#{no}")
   public void hitIncrement(Map map);
   
   @Select("SELECT * FROM ${table_name} "
		  +"WHERE no=#{no}")
   public SeoulVO seoulDetailData(Map map);
}

${table_name} => 이 코드를 이용해서 여러개의 테이블을 한번에 제어 할 수 있다
다만, 테이블들의 PK명칭이 다르기때문에 인덱스 기능은 사용을 못한다~!

차례로 목록 출력 코드, 페이지네이션 코드, 조회수 증가 코드, 상세보기 코드다 :)

📝 SeoulDAO 생성하기

package com.sist.dao;

import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;
import com.sist.mapper.*;
import com.sist.vo.*;
@Repository
public class SeoulDAO {
  // 스프링에서 구현된 Mapper 주소값 주입 요청 
  @Autowired
  private SeoulMapper mapper;
  

	   public List<SeoulVO> seoulListData(Map map)
	   {
		   return mapper.seoulListData(map);
	   }

	   public int seoulTotalPage(Map map)
	   {
		   return mapper.seoulTotalPage(map);
	   }
	   
	   public SeoulVO seoulDetailData(Map map)
	   {
		   mapper.hitIncrement(map);
		   return mapper.seoulDetailData(map);
	   }
  
}

📝 SeoulController 생성하기

package com.sist.web;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
// 화면 이동 
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class SeoulController {
   @GetMapping("seoul/list.do")
   public String seoul_list()
   {
	   return "seoul/list"; // Model
   }
   @GetMapping("seoul/detail_before.do")
   public String seoul_detail_before(int no,int type,RedirectAttributes ra,HttpServletResponse response)
   {
	   // 쿠키 생성 
	   String[] cmd={"","location","nature","shop"};
	   Cookie cookie=new Cookie(cmd[type]+no,String.valueOf(no));
	   cookie.setPath("/");
	   cookie.setMaxAge(60*60*24);
	   response.addCookie(cookie);
	   ra.addAttribute("no", no);
	   ra.addAttribute("type", type);
	   return "redirect:../seoul/detail.do"; // RedirectAttributes
   }
   @GetMapping("seoul/detail.do")
   public String seoul_detail(int no,int type,Model model)
   {
	   model.addAttribute("no", no);
	   model.addAttribute("type", type);
	   return "seoul/detail";
   }
}

Controller는 화면 전환용으로만 사용된다!
어떤 값을 받아서 어떤 동작을 보낼건지만 설정하면된다

추가로 쿠키를 생성하기 위해, 쿠키 생성 코드도 등록했다 !(아직 구현중!)

String[] cmd={"","location","nature","shop"}; => 이 코드를 이용해서 3개의 테이블을 제어한다.
if문이나 Switch문을 이용해도 괜찮지만 그러면 코드가 너무 길어지니까 배열을 사용했다!

📝 SeoulRestController 생성하기


import org.apache.commons.collections.map.HashedMap;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import com.sist.dao.*;
import com.sist.vo.*;
// 자바스크립트로 값 전송 
@RestController
public class SeoulRestController {
    @Autowired
    private SeoulDAO sDao;
    
    @GetMapping(value="seoul/list_vue.do",produces = "text/plain;charset=utf-8")
    // text/html (Ajax) , text/xml (XML), text/plain (JSON)
    public String seoul_list_vue(String page,String type,Model model)
    {
 	   if(page==null)
 		   page="1";
 	   if(type==null)
 		   type="1";
 	   
 	   int index=Integer.parseInt(type);
 	   String[] table_name={"","seoul_location","seoul_nature","seoul_shop"};
 	   
 	   int curpage=Integer.parseInt(page);
 	   Map map=new HashMap();
 	   int rowSize=12;
 	   int start=(rowSize*curpage)-(rowSize-1);
 	   int end=rowSize*curpage;
 	   
 	   map.put("start", start);
 	   map.put("end", end);
 	   map.put("table_name", table_name[index]);
 	   
 	   List<SeoulVO> list=sDao.seoulListData(map);
 	   int totalpage=sDao.seoulTotalPage(map);
 	   
 	   String result="";
 	   JSONArray arr=new JSONArray();//[] => {no,poster,title,curpage,totalpage},{no,poster,title}.....
 	   int k=0;
 	   for(SeoulVO vo:list)
 	   {
 		   JSONObject obj=new JSONObject();
 		   obj.put("no", vo.getNo());
 		   obj.put("title", vo.getTitle());
 		   obj.put("poster", vo.getPoster());
 		   
 		   if(k==0)
 		   {
 			   obj.put("curpage", curpage);
 	 		   obj.put("totalpage", totalpage);
 	 		   obj.put("type", type);
 		   }
 		   
 		   arr.add(obj);
 		   k++;
 	   }
 	   result=arr.toJSONString();
 	   return result;
    }
    
    @GetMapping(value="seoul/detail_vue.do",produces = "text/plain;charset=utf-8")
    public String seoul_detail_vue(int no,int type)
    {
    	String result="";
    	try
    	{
    		String[] table_name={"","seoul_location","seoul_nature","seoul_shop"};
    		Map map=new HashMap();
    		map.put("table_name", table_name[type]);
    		map.put("no", no);
    		
    		SeoulVO vo=sDao.seoulDetailData(map);
    		
    		JSONObject obj=new JSONObject();
    		obj.put("no",vo.getNo());
    		obj.put("title",vo.getTitle());
    		obj.put("address",vo.getAddress().substring(vo.getAddress().indexOf(" ")).trim());
    		obj.put("msg",vo.getMsg());
    		obj.put("poster",vo.getPoster());
    		
    		result=obj.toJSONString();
    		
    	}catch(Exception ex) 
    	{
    		ex.printStackTrace();
    	}
    	return result;
    }
    
    @GetMapping(value="seoul/cook_list.do" , produces = "text/plain;charset=utf-8")
    public String seoul_cook_list(String type,HttpServletRequest request)
    {
    	if(type==null)
    	{
    		type="1";
    	}
    	int t=Integer.parseInt(type);
    	String[] cook_name={"","location","nature","shop"};
    	String result="";
    	Cookie[] cookies=request.getCookies();
    	List<SeoulVO> list=new ArrayList<SeoulVO>();
    	if(cookies!=null)
    	{
    		for(int i=cookies.length-1;i>=0;i--)
    		{
    			if(cookies[i].getName().startsWith(cook_name[t]))
    			{
    				Map map=new HashMap();
    				String no=cookies[i].getValue();
    				map.put("no", no);
    				map.put("table_name", "seoul_"+cook_name[t]);
    				SeoulVO vo=sDao.seoulDetailData(map);
    				list.add(vo);
    			}
    		}
    	}
    	// list => JSON
    	return result;
    }
    
}

📝 list.jsp 생성하기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style type="text/css">
.container{
   margin-top: 30px;
}
.row {
   margin: 0px auto;
   width:100%
}

</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div class="container">
   <div id="seoul_list">
    <div class="row">
      <div class="text-center">
        <input type=button class="btn btn-lg btn-warning" value="서울 명소" @click="seoulChange(1)">
        <input type=button class="btn btn-lg btn-success" value="서울 자연" @click="seoulChange(2)">
        <input type=button class="btn btn-lg btn-info" value="서울 쇼핑" v-on:click="seoulChange(3)">
      </div>
    </div>
    <div style="height: 20px"></div>
    <div class="row" >
       <div class="col-md-4" v-for="vo in seoul_list">
		    <div class="thumbnail">
		      <a :href="'../seoul/detail_before.do?no='+vo.no+'&type='+type">
		        <img :src="vo.poster" alt="Lights" style="width:350px;height:250px;">
		        <div class="caption">
		          <p>{{vo.title }}</p>
		        </div>
		      </a>
		    </div>
		  </div>
    </div>
    <div class="row">
       <div class="text-center">
         <input type=button class="btn btn-lg btn-warning" value="이전" @click="prev()">
          {{curpage}} page / {{totalpage}} pages
         <input type=button class="btn btn-lg btn-success" value="다음" @click="next()">
       </div>
    </div>
   </div>
    <div style="height: 20px"></div>
    <div class="row" id="seoul_cookie">
    
    </div>
  </div>
  <script>
    const list=new Vue({
    	el:'#seoul_list',
    	data:{
    		curpage:1,
    		totalpage:0,
    		seoul_list:[],
    		type:1
    	},
    	mounted:function(){
    		this.send()
    	},
    	methods:{
    		send:function(){
    			let _this=this;
        		axios.get("http://localhost:8080/web/seoul/list_vue.do",{
        			params:{
        				page:_this.curpage,
        				type:_this.type
        			}
        		}).then(function(result){
        			_this.seoul_list=result.data;
        			_this.curpage=result.data[0].curpage;
        			_this.totalpage=result.data[0].totalpage;
        			_this.type=result.data[0].type;
        		})
    		},
    		seoulChange:function(no){
    			this.type=no;
    			this.curpage=1;
    			this.send();
    		},
    		prev:function(){
    			this.curpage=this.curpage>1?this.curpage-1:this.curpage;
    			this.send();
    		},
    		next:function(){
    			this.curpage=this.curpage<this.totalpage?this.curpage+1:this.curpage;
    			this.send();
    		}
    	}
    })
    const cook=new Vue({
    	el:'#seoul_cookie',
    	data:{
    		seoul_cook:[]
    	}
    })
  </script>
</body>
</html>

📝 detail.jsp 생성하기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style type="text/css">
.container{
   margin-top: 30px;
}
.row {
   margin: 0px auto;
   width:700px
}

</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
   <div class="container">
     <div class="row" id="seoul_detail">
       <table class="table">
         <tr>
           <td class="text-center">
            <img :src="seoul_detail.poster" style="width: 700px;height: 250px">
           </td>
         </tr>
         <tr>
           <td><h3>{{seoul_detail.title}}</h3></td>
         </tr>
         <tr>
           <td><h5>{{seoul_detail.msg}}</h5></td>
         </tr>
         <tr>
           <td><h4>{{seoul_detail.address}}</h4></td>
         </tr>
         <tr>
           <td class="text-right">
             <input type=button class="btn btn-xs btn-primary" value="목록"
              @click="javascript:history.back()"
             >
           </td>
         </tr>
       </table>
     </div>
     <div style="height: 20px"></div>
     <div class="row" id="seoul_reply">
     
     </div>
   </div>
   <script>
    new Vue({
    	el:'#seoul_detail',
    	data:{
    		no:${no},
    		type:${type},
    		seoul_detail:{}
    	},
    	mounted:function(){
    		let _this=this;
    		axios.get("http://localhost:8080/web/seoul/detail_vue.do",{
    			params:{
    				no:_this.no,
        			type:_this.type
    			}
    		}).then(function(result){
    			_this.seoul_detail=result.data
    		})
    	}
    })
   </script>
</body>
</html>

💻 실행결과 확인하기

✔️ 장소 목록 출력 기능

상단의 버튼을 클릭하면, 해당 테이블의 데이터로 이동한다!

✔️ 장소 상세보기 기능


상세보기 기능을 통해, 각 장소의 세부 정보를 파악할 수 있다.

'목록' 버튼을 클릭하면, 목록으로 이동한다!😁

profile
안녕하세요

0개의 댓글