Front-end/React

국비 React - Spring과 연동하기

이안92 2020. 11. 17. 19:15
반응형

2020.11.17(화)

 

SpringAOPProject3

iancoding.tistory.com/120

 

Spring 15일차 - AOP

2020.11.17(화) mvnrepository.com/artifact/javax.validation/validation-api/2.0.1.Final Maven Repository: javax.validation » validation-api » 2.0.1.Final javax.validation validation-api 2.0.1.Final..

iancoding.tistory.com

 

src/main/java

com.sist.web

ReactController

package com.sist.web;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.net.URLEncoder;
import java.util.*;
import com.sist.dao.*;

@RestController
@CrossOrigin("http://localhost:3000")
public class ReactController {
    @Autowired
    private RecipeDAO dao;
    
    @RequestMapping("recipe/list.do")
    public String recipe_list(String page) throws Exception{
        if(page==null)
            page="1";
        int curpage=Integer.parseInt(page);
        Map map=new HashMap();
        int rowSize=15;
        int start=(rowSize*curpage)-(rowSize-1);
        int end=rowSize*curpage;
        map.put("start", start);
        map.put("end", end);
        
        List<RecipeVO> list=dao.recipeListData(map);
        String json="";
        JSONArray arr=new JSONArray();
        for(RecipeVO vo:list){
            JSONObject obj=new JSONObject();
            obj.put("no", vo.getNo());
            obj.put("title", vo.getTitle());
            obj.put("poster", vo.getPoster());
            obj.put("chef", vo.getChef());
            arr.add(obj);
        }
        /*
         * [] JSONArray
         * {} JSONObject
         * 20개 모아서 한번에 보내줌 =>[{},{},{},....]
         * [{no:1,title:'',poster:'',chef:''},{},{},...]
         * MongoDB는 JSON기반
         */
        json=arr.toJSONString();
        System.out.println(json);
        return json;
    }
}

 

com.sist.dao

RecipeVO

package com.sist.dao;

public class RecipeVO {
    private int no;
    private String title, poster, chef, link;
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getPoster() {
        return poster;
    }
    public void setPoster(String poster) {
        this.poster = poster;
    }
    public String getChef() {
        return chef;
    }
    public void setChef(String chef) {
        this.chef = chef;
    }
    public String getLink() {
        return link;
    }
    public void setLink(String link) {
        this.link = link;
    }
    
}

 

RecipeMapper (interface)

package com.sist.dao;
import java.util.*;

import org.apache.ibatis.annotations.Select;
public interface RecipeMapper {
    @Select("SELECT no,title,poster,chef,num "
            +"FROM (SELECT no,title,poster,chef,rownum as num "
            +"FROM (SELECT no,title,poster,chef "
            +"FROM recipe ORDER BY no ASC)) "
            +"WHERE num BETWEEN #{start} AND #{end}")
    public List<RecipeVO> recipeListData(Map map);
    @Select("SELECT CEIL(COUNT(*)/20.0) FROM recipe")
    public int recipeTotalPage();
}

 

RecipeDAO

package com.sist.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.*;
@Repository
public class RecipeDAO {
    @Autowired
    private RecipeMapper mapper;
    public List<RecipeVO> recipeListData(Map map){
        return mapper.recipeListData(map);
    }
    public int recipeTotalPage(){
        return mapper.recipeTotalPage();
    }
}

 

WEB-INF/config

application-context.xml에 mapper추가

<bean id="mapper3"
     class="org.mybatis.spring.mapper.MapperFactoryBean"
     p:mapperInterface="com.sist.dao.RecipeMapper"
     p:sqlSessionFactory-ref="ssf"
 />

 

JSON한글깨짐 방지

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

 

C:\JetBrains\WebStorm 2020.2.3\bin/webstorm64

 

File-New-Project

This Window클릭

 

spring-react-project/public/

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div class="container-fluid" id="root">

    </div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

 

package.json에

"web-vitals": "^0.2.4" 추가하고 팝업 다운로드 확인

{
  "name": "spring-react-project",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.1.2",
    "@testing-library/user-event": "^12.2.2",
    "axios": "^0.21.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.0",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

 

src

App.js

import React,{Component} from 'react'
import axios from 'axios'

class App extends Component{
  constructor(props) {
    super(props);
    this.state={
      recipe:[],
      detail:{},
      totalpage:1,
      page:1
    }

  }
  componentDidMount() {
    axios("http://localhost/web/recipe/list.do",{
      params:{
        page:1
      }
    }).then(response=>{
      this.setState({recipe:response.data})
    })
  }
  render() {
    const html=this.state.recipe.map(m=>
        <div className="col-md-4">
          <div className="thumbnail">
              <img src={m.poster} alt="Lights" style={{"width":"100%"}}/>
                <div className="caption">
                  <p>{m.title}</p>
                </div>
          </div>
        </div>
    )
    return (
        <div className={"row"}>
          {html}
        </div>
    )
  }
}
export default App;

 

componentDidMount() - 스프링에서 긁어옴

render() - 출력

 

* 주의사항

스타일은 {{ : }} 안에 / "{m.title}"에서 ""로 감싸면안됨

 

터미널에서 npm start로

 

반응형