JSON Array

  • json 배열은 여러 개의 json 형식의 데이터가 배열 형태로 저장된 자료를 의미
  • [ {”key1”:”value1”,”key2”:”value2”,…} ,{”key1”:”value1”,”key2”:”value2”,…}, … ]

#1_DTO

public class PhotoDto {
	private String name;
	private String photo;

//getter,setter생략

	public PhotoDto(String name,String photo) {
		super(); //생략가능,하지만 위치는 맨위에
		this.name=name;
		this.photo=photo;
	}
}
  • 일반적 DTO와 같지만, 명시적 생성자 선언
  • 명시적 생성자를 통해 생성과 동시에 인자 값에 해당하는 값을 각 멤버 변수에 대입 (즉 setter의 기능을 생성자로 대체, 따라서 위 DTO에서 setter는 필요 없음)
  • Spring Framework의 특성 중, Key, Value 값만 쌍으로 전달하면 어떠한 방식이든 json 형식으로 변환 가능 (DTO에 Key(name), Value(photo) 값을 담아 전달하는 방식 시도)

Controller_Common

@Controller
public class JsonTestController {

	@GetMapping("/list3")
	public @ResponseBody List<PhotoDto> list3(){
		
		List<PhotoDto> list=new ArrayList<PhotoDto>();
		
		list.add(new PhotoDto("카톡임티1", "b1.png"));
		list.add(new PhotoDto("카톡임티2", "b3.png"));
		list.add(new PhotoDto("카톡임티3", "b5.png"));
		list.add(new PhotoDto("카톡임티4", "b7.png"));
		list.add(new PhotoDto("카톡임티5", "b9.png"));
		
		return list;
	}
}
  • 매핑 주소를 지정하고, @Responsebody를 통해 데이터를 json 형식으로 해당 매핑 주소로 전달 (어노테이션의 위치는 변환할 자료형 앞)
  • 전술했듯 Spring Framework는 Key, Value의 값을 쌍으로 전달할 수만 있으면 모두 json 형식으로 변환 가능 (Map, DTO, List 등) → DTO에 값을 담아 매핑 주소로 전달
  • 해당 매핑 주소에는 json 배열 형태의 데이터가 저장

View_Print

<body>
	<!--ex3번 예제-->
	<button type="button" id="btn3">list3 json 배열</button>
	<div id="out3"></div>
	
	<script type="text/javascript">
		$("#btn3").click(function(){
			
			$.ajax({
				type:"get",
				url:"list3",
				dataType:"json",
				success:function(data){
					
					var s="";
					
					$.each(data,function(i,elt){
						s+="<figure>";
						s+="<img src='image/avata/"+elt.photo+"' width=100>";
						s+="<figcaption><b>";
						s+=elt.name;
						s+="</b></figcaption>";
						s+="</figure>";
					});
					$("#out3").html(s);
				}
			});
		});
	</script>
</body>
  • json(혹은 json 배열) 데이터를 사용하기 위해 ajax 이벤트 활용
  • 단순한 json 데이터와 달리 json 배열 데이터는 ajax에서 호출 시 ‘$.each(json데이터,함수)’ 사용

#2_Controller_Only For JSON Parsing

public class JsonTest2Controller {

	@GetMapping("/list4")
	public Map<String, Object> list4(@RequestParam String name){

		Map<String, Object>map=new HashMap<String, Object>();
		
		List<PhotoDto> list=new ArrayList<PhotoDto>();
		
		list.add(new PhotoDto("카톡임티1", "b1.png"));
		list.add(new PhotoDto("카톡임티2", "b3.png"));
		list.add(new PhotoDto("카톡임티3", "b5.png"));
		list.add(new PhotoDto("카톡임티4", "b7.png"));
		list.add(new PhotoDto("카톡임티5", "b9.png"));
		map.put("name", "없는 이름");
		map.put("photo", "no.png");
		
		for(PhotoDto dto:list) {
			if(name.equals(dto.getName())) {
				map.put("name", dto.getName());
				map.put("photo", dto.getPhoto());
			}
		}
		
		return map;
	}
}
  • json 파싱 전용 Controller에서는 어노테이션 선언하지 않음
  • Map 방식으로 json 데이터로 변환 후 전달 (하나의 데이터만 전달하므로 배열은 아님)
  • 기본적으로 지정된 데이터가 조건문에 따라 유동적으로 변하도록 설계 (List에 저장되지 않은 값이 RequestParam될 시 그대로, 저장된 값이 넘어올 시 해당 값으로 변함)

View_Print

<body>
	<!--Ex4번 예제-->
	<h4>메뉴명을 입력후 엔터를 쳐주세요</h4>
	<input type="text" id="search" class="form-control">

	<h2 id="fname"></h2>
	<img alt="" src="" id="photo">
	
	<script type="text/javascript">
		$("#search").keydown(function(e) {
			if(e.keyCode&&e.keyCode==13) {

				var name=$(this).val();
	
				$.ajax({
					type:"get",
					url:"list4",
					dataType:"json",
					data:{"name":name},
					success:function(data){
	
						$("#photo").attr("src","image/avata/"+data.photo);
						$("#fname").html(data.name);
					}
				});
			}
		});
	</script>
</body>
  • ajax 작동 시 전달할 값이 있으므로 data 전달 (전달된 값에 따라 json 반환 데이터 변경)
  • enter 키 입력 조건 숙지 필요 (enter 키는 keyCode 13)

File Upload & JDBC

Ready Settings

  • pom.xml, servlet-context.xml, root-context.xml 설정 변경 (1011의 File Upload와 JDCB의 설정을 모두)
  • Mapper와 mybatis-config 파일 생성
  • 파일 업로드용 가상 경로를 위한 폴더 생성
  • DB에 Table 생성

DTO & DAO

public class InfoDto {
	private String num;
	private String name;
	private String driver;
	private String addr;
	private String photo;
	private Timestamp gaipday;
	
	//getter,setter생략
}
  • DB 테이블의 속성을 멤버 변수로 담은 DTO 선언
public interface InfoInter {

	public int getTotalCount();
	public void insertMyInfo(InfoDto dto);
	public List<InfoDto> getAllDatas();
	public InfoDto getData(String num);
	public void updateMyifo(InfoDto dto);
	public void deleteMyInfo(String num);
}
  • DAO의 메서드를 추상화한 Interface 선언 (DAO 클래스에서 Override)
@Repository
public class InfoDao implements InfoInter {
	
	@Autowired
	SqlSession session;
	
	@Override
	public int getTotalCount() {
		return session.selectOne("selectTotalCountOfMyInfo");
	}

	@Override
	public void insertMyInfo(InfoDto dto) {
		session.insert("insertOfmyInfo",dto);
	}

	@Override
	public List<InfoDto> getAllDatas() {
		return session.selectList("selectAllOfMyInfo");
	}

	@Override
	public InfoDto getData(String num) {
		return session.selectOne("getDataOfMyInfo", num);
	}

	@Override
	public void updateMyifo(InfoDto dto) {
		session.update("updateOfMyInfo",dto);
	}

	@Override
	public void deleteMyInfo(String num) {
		session.delete("deleteOfMyInfo",num);
	}
}
  • root-context.xml에서 설정한 SqlSession 객체를 통해 SQL문 접근 및 통제

SQL DML _ MyBatis & Mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>
	<typeAliases>
		<typeAlias alias="idto" type="spring.mvc.friday.InfoDto"/>
	</typeAliases>
</configuration>
  • mybatis를 통해 사용할 자료형의 alias 설정 (여기서는 DTO 멤버의 alias 지정)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="spring.mvc.friday.InfoDao">

	<!--일반적 sql문은 기존과 동일하게 작성 : 생략-->

	<!--조건에 따른 sql문 작성-->
	<update id="updateOfMyInfo" parameterType="idto">
		update myinfo set name=#{name},driver=#{driver},addr=#{addr}
		<if test="photo!=null">
			,photo=#{photo}
		</if>
		where num=#{num}
	</update>

</mapper>
  • DB와 연결하여 sql을 조작하고 데이터를 교환하는 Mapper
  • Mapper의 파일 형식은 xml이므로 조건에 따라 sql문을 변환하고자 할 때, java같은 조건문 사용 불가
  • 따라서 <mapper>태그의 조건문인 <if test=””>태그 사용 (test 속성에 조건문을 String 형식으로 작성, 조건 일치 시 해당 태그 내의 sql문 삽입, 조건 불일치 시 sql문 생략) → 이를 통해 조건에 따라 sql문 변경 가능

Controller_Member

@Controller
public class InfoController {
	
	@Autowired
	InfoInter inter;

	//메서드는 후술
}
  • 여기서 @Autowired는 @Repository와 자동 연결하여 객체를 생성하는 기능
  • @Repository는 DAO를 Beans에 등록하는 어노테이션인데, Interface는 등록 불가, 오로지 클래스만 등록 가능
  • 따라서 인터페이스를 생성하더라도 클래스를 통해 생성하므로, 다형성에 따라 인터페이스를 상속한 클래스의 멤버를 호출 (즉 interface가 아닌 DAO 멤버 사용)

Controller_Simple

@Controller
public class InfoController {

	//이후로 InfoInter 호출 생략

	@GetMapping("/info/list")
	public String list(Model model) {
		
		int count=inter.getTotalCount();
		List<InfoDto>list=inter.getAllDatas();
		
		model.addAttribute("list",list);
		model.addAttribute("count", count);
		
		return "info/infoList";
	}
	
	@GetMapping("/info/addform")
	public String add() {
		return "info/addForm";
	}

	@GetMapping("/info/updateform")
	public String updateForm(Model model,@RequestParam String num) {
		
		InfoDto dto=inter.getData(num);
		
		model.addAttribute("dto",dto);
		
		return "info/updateForm";
	}
}
  • 간단한 메서드는 설명 생략

Controller_Insert

@Controller
public class InfoController {

	@PostMapping("/info/insert")
	public String insert(@ModelAttribute InfoDto dto,
			@RequestParam MultipartFile upload,
			HttpSession session) {
		
		String path=session.getServletContext().getRealPath("/resources/image/");
		
		System.out.println(path);
		
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
		
		String photo="";
		
		//사진선택을 안했을경우 no..
		if(upload.getOriginalFilename().equals("")) {
			photo="no";
		}else {
			String fName=upload.getOriginalFilename();
			fName=sdf.format(new Date())+"_"+fName;
			
			photo=fName;
			
			//업로드 슬래쉬는 1개 역슬래쉬는 2개
			try {
				upload.transferTo(new File(path+"/"+photo));
			} catch (IllegalStateException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//dto에 photo 넣기
		dto.setPhoto(photo);
		
		//insert
		inter.insertMyInfo(dto);
		
		return "redirect:list";
	}
}
  • 매핑 메서드의 인자로써 필요한 객체
    • insert하고자 하는 값을 담은 DTO
    • 파일 업로드를 위한 MultipartFile 객체
    • realPath를 지정, 출력하기 위한 HttpSession 객체
  • HttpSession 객체의 getRealPath() 메서드를 통해 실제 저장 경로 확보 (인자 값은 저장될 파일의 절대 경로)
  • MultipartFile 객체의 getOriginalFilename() 메서드를 통해 실제 저장될 파일명 확보 (파일 미업로드 시 예외처리, 중복 파일 업로드로 인한 파일 생략처리 등을 위해 파일명 조작 가능)
    • 미업로드 예외 처리 : 조건문을 통해 미업로드 시 DB에 저장될 값 지정 / try ~ catch문 이용

    • 중복 업로드 생략 처리 : 업로드 시간을 파일명에 추가

      → 처리된 파일명으로 DTO 멤버 값 변경 후 insert

  • MultipartFile 객체의 transferTo(new File( )) 메서드를 이용해 실제로 파일을 가상 경로에 업로드 (File 객체의 인자 값은 실제 파일에 도달하기까지의 경로)

Controller_Update

@Controller
public class InfoController {

	@PostMapping("info/update")
	public String update(@ModelAttribute("dto")InfoDto dto,
			@RequestParam MultipartFile upload,
			HttpSession session) {
		
		String photo=inter.getData(dto.getNum()).getPhoto();
		System.out.println(photo);

		if(!photo.equals("no")) {
			String path=session.getServletContext().getRealPath("/resources/image/");
			
			File file=new File(path+"/"+photo);
			file.delete();
		}
		
		String path=session.getServletContext().getRealPath("/resources/image/");
		System.out.println(path);
		
		String photoName;
		
		if(upload.getOriginalFilename().equals("")) {
			photoName=null;
		}else {
			photoName=upload.getOriginalFilename();
			
			try {
				upload.transferTo(new File(path+"/"+photoName));
			} catch (IllegalStateException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//dto의 photo에 업로드한 photoname 넣어주기
		dto.setPhoto(photoName);
		
		inter.updateMyifo(dto);
		
		return "redirect:list";
	}
}
  • <input type=”file”>은 value 속성으로 기본값 지정 불가 (Mapper에서 sql문을 조건에 따라 조작하여 null 값을 기본값으로 처리)
  • 그 외에는 insert와 거의 동일
  • 하지만 가상 경로에 저장된 파일은 변경되지 않고 추가되어 용량에 부담 → 기존 파일 삭제 필요
    • update 시 파일 변경 없음 : 변경 사항 없으므로 삭제 불필요
    • 변경 시 : File() 객체를 이용해 기존 파일까지의 경로 지정 후 delete() 메서드를 이용해 실제 파일 삭제 (실제 저장된 파일명을 정확히 지정 필요 → .getData(dto.getNum()).getPhoto() )

Controller_Delete

@Controller
public class InfoController {

	@GetMapping("info/delete")
	public String delete(@RequestParam String num,HttpSession session) {
		
		String photo=inter.getData(num).getPhoto();
		
		if(!photo.equals("no")) {
			String path=session.getServletContext().getRealPath("/resources/image/");
			
			File file=new File(path+"/"+photo);
			file.delete();
		}
		inter.deleteMyInfo(num);
		
		return "redirect:list";
	}
}
  • DB 삭제는 간단하지만 실제 저장 경로상의 파일도 삭제할 필요 있음
  • update에서 실제 파일 삭제한 것과 동일한 방법 사용

View_Insert Form

<form action="insert" method="post" enctype="multipart/form-data">
	<table>
		
		<!-- text 업로드 생략 -->

		<tr>
			<th>사진</th>
			<td>
				<input type="file" name="upload" style="width: 250px;" class="form-control">
			</td>
		</tr>
		<tr>
			<th>운전면허</th>
			<td>
				<input type="radio" name="driver" value="있음">있음&nbsp;
				<input type="radio" name="driver" value="없음" checked>없음
			</td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<button type="submit">DB저장</button>
				<button type="button"	onclick="location.href='list'">목록</button>
			</td>
		</tr>
	</table>
</form>
  • 파일 업로드를 위해 <form>에 enctype="multipart/form-data" 속성 필수
  • Radio Box의 form 있음

View_Update Form

<form action="update" method="post" enctype="multipart/form-data">
	<input type="hidden" name="num" value="${dto.num }">
	<table>
		<tr>
			<th>사진</th>
			<td>
				<input type="file" name="upload" style="width: 250px;" class="form-control">
			</td>
		</tr>
		<tr>
			<th>운전면허</th>
			<td>
				<input type="radio" name="driver" value="있음" ${dto.driver=="있음"?"checked":"" }>있음&nbsp;
				<input type="radio" name="driver" value="없음" ${dto.driver=="없음"?"checked":"" }>없음
			</td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<button type="submit">DB저장</button>
				<button type="button"	onclick="location.href='list'">목록</button>
			</td>
		</tr>
	</table>
</form>
  • update는 insert와 달리 튜플을 특정해야 하므로 특정용 속성(num) 전달 필수
  • Radio Box도 기본값을 선택값으로 변경 필요 → 삼항연산자 이용

View_List

<!-- 일반적인 방법 이용 -->
  • <c:forEach> 및 <c:if> 사용
profile
초보개발자

0개의 댓글