자바 기본 데이터 타입의 경우 초기화 값을 정의해주지 않고 메모리 공간만 확보할 경우

쓰레기 값이 아닌 초기 값이 들어간다

(C, C++ 같은 경우 쓰레기 값이 들어간다. 쓰레기 값은 성능에 영향이 없다)

(초기 값이 들어가는 만큼 자바에서는 변수 선언 만으로 성능에 영향을 주지만 유의미한 수준은 아니다)

반복문 등을 돌릴때 기본값을 빼주는 식으로 응용할 수 있다

일단 기본값이 아닌 데이터를 넣었는데 아래  값이 나오면 의심해봐야 한다

 

Data Type Default Value (for fields)
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String (or any object)   null
boolean false

 

 

기타)

C, C++ 쓰레기 값의 의미  
0xcdcdcdcd                 새로 메모리를 할당(malloc)을 받고 초기화를 하지 않은 상태의 값
0xcccccccc                  새로 지역 변수를 선언한 후 초기화를 하지 않은 상태의 값
(전역 변수는 초기화를 하지 않아도 첫 선언 당시 값은 0)
0xeefeeefe                   메모리를 할당(malloc)은 뒤 사용을 다 맞춘 후 해제(free)처리가 된 상태의 값
0xfdfdfdfd                     할당(malloc)된 메모리의 주변 값

 

https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html

 

StringBuilder (Java Platform SE 8 )

Inserts the string into this character sequence. The characters of the String argument are inserted, in order, into this sequence at the indicated offset, moving up any characters originally above that position and increasing the length of this sequence by

docs.oracle.com

 

 

https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html

 

Math (Java Platform SE 8 )

Returns the value of the first argument raised to the power of the second argument. Special cases: If the second argument is positive or negative zero, then the result is 1.0. If the second argument is 1.0, then the result is the same as the first argument

docs.oracle.com

 

 

https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html

 

Collection (Java Platform SE 8 )

Compares the specified object with this collection for equality. While the Collection interface adds no stipulations to the general contract for the Object.equals, programmers who implement the Collection interface "directly" (in other words, create a clas

docs.oracle.com

 

 

 가끔 리마인드 하려고 블로그에 박제

웅앵웅

 

화이트라벨 어쩌구 하면서 서버나 JDBC 드라이버의 타임존을 설정하라고 한다

 

 

 

spring boot의 config application 외부 설정 파일로 가서 url에 서버타임존을 위처럼 설정한다

 

 

 

 

이클립스 마켓플레이스 창을 띄운다 (위에 탭에 잘 뒤져보면 있음)

 

이클립스 엑스엠엘 편집기와 도구스

 

설치한다

 

XML 파일에서 컨트롤 + 스페이스로 잘나오나 확인한다

 

 

잘나옴

 

연결 정보 (DataSource) 는 Spring만 사용하면 개인이 만든 xml 설정 파일로 빼주고, Spring boot 사용시에는 application.config 파일에 작성해주고 JdbcTemplate 객체를 인스턴스화해서 Jdbctemplate에서 미리 만들어둔 다양한 query 메소드에 SQL문이나 DB에서 데이터를 받아오는데 필요로 하는 Entity 클레스 담아서 필요한 변수타입으로 만들어 controller로 보내주면 된다

 

그러면 connect나 statement, resultset, next(), set, get 같은 건 템플릿이 내부적으로 알아서 처리해줌

 

 

 

controller에서는 spring 내부적으로 가지고 있는 멤버 Model (haspMap 구성과 비슷하다) 을 사용해 그대로 담아서 view 단으로 넘겨주면 된다

dispatcher, forward 뭐 그런건 자기가 알아서 넘겨줌

session을 사용해 상태유지를 하고 싶다면 관련된 @SessionAttribute 같은 어노테이션을 써도 되고 내부적으로 servlet을 가지고 있으니 HttpSession을 Model 대신 인자로 가져와서 써도된다


< POST 파일 업로드 설정하기 >


post의 인코딩 타입을 마찬가지로 쿼리 문자열이 아닌 바이너리 데이터를 전송할 수 있도록
html과 server를 모두 multipart/form-data 로 바꿔줘야 한다


참고1 - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/commons/CommonsMultipartResolver.html

참고2 - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/commons/CommonsFileUploadSupport.html



[멀티파트 설정]


commons-fileupload 라이브러리 설치
[pom.xml]
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>



서버 DI 설정
[servlet-context.xml]
<bean id="multipartResolver
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- setting maximum upload size -->
<property name="maxUploadSize" value="314572800" />
</bean>

>> CommonsMultipartResolver 객체 생성해서 setMaxUploadSize DI 해주고 300Mb까지 허용

setMaxUploadSize(long maxUploadSize) 업로드 허용할 전체 파일 사이즈
setMaxUploadSizePerFile(long maxUploadSizePerFile) 업로드 허용할 개개의 파일 사이즈
setMaxInMemorySize(int maxInMemorySize) 업로드 시 사용할 임시 메모리 사이즈
setUploadTempDir(Resource uploadTempDir) 임시 메모리 사이즈를 초과할 경우 저장할 임시 디렉토리

MaxInMemorySize, UploadTempDir 은 딱히 지정해주지 않아도 톰캣이 알아서 한다
MaxUploadSize 만 설정해도 큰 문제는 없다

 


클라이언트 인코딩 타입 설정
[html]
<form method="post" action="reg" enctype="multipart/form-data">

 

 

 

서버 컨트롤러로 제대로 오는지 확인
@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, MultipartFile file, String category, String[] foods, String food) {

    long Size = file.getSize();
    String fileName = file.getOriginalFilename();

    System.out.printf("fileName:%s, fileSize:%d\n", fileName, Size);

    return String.format("title:%s<br>content:%s<br>category:%s<br>" , title, content, category);
}

 

 


< POST 물리경로 얻기와 파일 저장하기 >


저장 경로를 얻는 방법

@Autowired
ServletContext ctx;
또는
@Autowired
private HttpServletRequest request;

절대 경로 얻기
String realPath = ctx.getRealPath("/upload");
또는
String realPath = request.getServletContext.getRealPath("/upload");

저장하기
File saveFile = new File(realPath);
multipartFile.transferTo(saveFile);

함수 내에서만 사용할거라면 인자로 HttpServletRequest request 객체를 받아오면 되겠고
컨트롤러 내에 여러 함수에서 사용하겠다면 멤버로 서블렛컨텍스트 객체를 얻어놓고 사용하면 되겠다

 

 

ex)
// Spring Ioc 컨테이너는 ServletContext를 이미 가지고 있다 Autowired만 해서 쓰면 됨
@Autowired  
private ServletContext ctx;

@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, MultipartFile file, String category, String[] foods, String food, HttpServletRequest request) {
    long Size = file.getSize();
    String fileName = file.getOriginalFilename();

    // ServletContext ctx = request.getServletContext();
    String webPath = "/static/upload";
    String realPath = ctx.getRealPath(webPath);

    return "";

}

 

realPath : C:\project\jsp\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\webprj\static\upload

콘솔에 나오는 경로는 보면 알겠지만 실제로 프로젝트를 진행하고 있는 경로가 아니라 배포를 위한 모든 작업을 마친 뒤의 배포시의 경로가 나오고 있는 것을 알 수 있다
실제 서비스 될 때는 위의 경로에 파일이 저장되고 사용된다

(그러니 테스트 할 때도 엉뚱한데서 찾지말고 배포 폴더에서 찾자)


단일 저장
@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, MultipartFile file, String category, String[] foods, String food, HttpServletRequest request) throws IllegalStateException, IOException {

    long Size = file.getSize();
    String fileName = file.getOriginalFilename();

    ServletContext ctx = request.getServletContext();
    String webPath = "/static/upload";
    String realPath = ctx.getRealPath(webPath);


    File savePath = new File(realPath);
    if(!savePath.exists())
    savePath.mkdirs();

    realPath += File.separator + fileName;
    File saveFile = new File(realPath);

    file.transferTo(saveFile);

    return "";

 

}





< POST 다중 파일 업로드 처리하기 >


name을 동일하게 만들어 배열로 받는다

[html]
                                <tr>
                                    <th>첨부파일</th>
                                    <td colspan="3" class="text-align-left text-indent"><input type="file"
                                            name="files" /> </td>
                                </tr>
                                <tr>
                                    <th>첨부파일</th>
                                    <td colspan="3" class="text-align-left text-indent"><input type="file"
                                            name="files" /> </td>
                                </tr>


배열로 받아 for문으로 돌린다

@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, MultipartFile[] files, String category, String[] foods, String food, HttpServletRequest request) throws IllegalStateException, IOException {

    for(MultipartFile file : files) {

        if(file.getSize() == 0) continue;
        // 파일이 0개 또는 한개만 올라올 경우

        long Size = file.getSize();
        String fileName = file.getOriginalFilename();
        ServletContext ctx = request.getServletContext();
        String webPath = "/static/upload";
        String realPath = ctx.getRealPath(webPath);

        File savePath = new File(realPath);
        if(!savePath.exists())
        savePath.mkdirs();

        realPath += File.separator + fileName;
        File saveFile = new File(realPath);

        file.transferTo(saveFile);
    }


    return "";


}


if(file.getSize() == 0) continue;
파일을 한개나 안올릴수도 있으니까 조건처리 해줘야 한다
(안하면 destination files 어쩌구 하면서 있지도 않은거 작업한다고 뭐라 함)





< POST 매핑과 Redirection >


POST를 통해 파일을 주고받을 때는 해당 맵핑 주소에서 다음과 같은 에러 메시지를 볼 수 있다
Request processing failed; nested exception is java.lang.NullPointerException: Cannot read the array length because "files" is null

함수에서 파일 저장에 files를 받아 활용하고 있기 때문인데 GET 요청 시에도 POST submit (데이터 전송)이 필요한 해당 코드가 실행되기 때문이다
클라이언트의 GET 요청시에만 이루어질 함수, POST 요청시에만 이루어질 함수 등으로 구분해 줄 필요가 있다

메소드 내에서 NullPointetrException이 뜨는 코드를
if (request.getMethod().equals("POST")) { }
조건문으로 감싸주는 방법도 있고


서블렛의 doGet, doPost 메소드를 사용할 때처럼 두 종류로 구분하는 방법이 있다


Spring 3.0 이전 버전

@RequestMapping("list")
public String list() {

return "admin.board.notice.list";
}

@RequestMapping(value="reg", method=RequestMethod.GET)
public String reg() {

return "admin.board.notice.reg";
}


@RequestMapping(value="reg", method=RequestMethod.POST)
public String reg() {
// 리디렉션 : list 페이지로
return "redirect:list";
// 포워딩 : return "admin/notice/reg";
}

post는 데이터 전송 후 새로운 페이지로 redirect하는 것이 기본인데, 클라이언트의 새로고침이나 뒤로가기 등을 통한 post 재요청을 막기 위해서도 필요하다 

( 뒤로가기나 새로고침은 브라우저의 cashe를 사용해 요청되는데(양식 재제출 요청) 이때 post 요청시의 데이터가 cashe에 남아있고 컨트롤러에서는 해당 cashe 데이터에 대한 처리가 없다면 중복된 데이터가 DB에 등록되는 일이 발생한다. DB에 넣기전에 DB 데이터와 동일한지 조건처리 하는 방법도 있으나 DAO 에서 해야할 일을 controller 단에서부터 굳이 넘겨와서 하는 MVC 모델 자체를 깨버리는 문제도 있고 transaction 처리도 생각하면 그냥 평범하게 Redirect 하는 게 기본이다 )


Spring 3.0 이후 버전

@RequestMapping("list")
public String list() {

return "admin.board.notice.list";
}

@GetMapping("reg")
public String reg() {

return "admin.board.notice.reg";
}


@PostMapping("reg")
public String reg() {
// 리디렉션 : list 페이지로
return "redirect:list";
// 포워딩 : return "admin/notice/reg";
}


어노테이션이 늘어나서 편해짐

 

 

 



< POST 입력 방법 >


(jsp 말고 static html 쓰려면 외부설정.xml에 mvc schema로 resources 기본경로를 /static/ 으로 했으니 해당부분 감안하고 url 입력해야 html 문서 제대로 열림)

html 
form action="controller에 맵핑된 url" method="post"
button type="submit"
input 입력값의 name 설정값이 controller의 매개변수가 된다
(매개변수명 바꿔주고 싶으면 @RequestParam 쓰면 됨)

@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content) {

return String.format("title:%s<br>content:%s<br>" , title, content);
}

기본 사용법은 GET 방식과 같다




< POST 콤보박스 값 입력 >


                                <tr>
                                    <th>카테고리</th>
                                    <td class="text-align-left text-indent text-strong text-orange" colspan="3">
                                        <select name="category">
                                         <option value="1">카테고리1</option>
                                         <option value="2">카테고리2</option>
                                         <option value="3">카테고리3</option>
                                         <option value="4">카테고리4</option>
                                        </select>
                                    </td>
                                </tr>


@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, String category) {

return String.format("title:%s<br>content:%s<br>category:%s<br>" , title, content, category);
}


>> option에 value 속성이 있으면 value 값이, 없으면 option 의 text 요소(카테고리1)가 전달된다
>> 범용적으로 value를 사용해 식별자를 부여하고 DB의 content list 를 받아오게 된다




< POST 체크박스와 라디오버튼 값 입력 >


-체크박스-

                                <tr>
                                    <th>좋아하는 음식</th>
                                    <td class="text-align-left text-indent text-strong text-orange" colspan="3">
                                     <input type="checkbox" name="foods" value="1" id="ch1"><label for="ch1">자장면</label>
                                     <input type="checkbox" name="foods" value="2" id="ch2"><label for="ch2">짬뽕</label>
                                     <input type="checkbox" name="foods" value="3" id="ch3"><label for="ch3">볶음밥</label>
                                     <input type="checkbox" name="foods" value="4" id="ch4"><label for="ch4">탕수육</label>
                                    </td>
                                </tr>


@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, String category, String[] foods) {
System.out.println(category);
for(String food : foods)
  System.out.println(food);

return String.format("title:%s<br>content:%s<br>category:%s<br>" , title, content, category);
}


>> name을 동일하게 주어 배열로 받을 수 있다
>> input의 value 값을 보낸다 (value 속성을 주지 않을 경우 on 이라는 문자열을 보냄)
>> 배열로 받고 for문을 돌렸는데 어떠한 값도 체크하지 않았을 경우 NullPointerException을 뱉어낸다
(물론 for 문을 돌리지 않으면 null 값이 들어있는 상태로 오류는 뱉어내지 않는다. 제어문으로 제어하자)



-라디오버튼-

                                <tr>
                                    <th>가장 좋아하는 음식</th>
                                    <td class="text-align-left text-indent text-strong text-orange" colspan="3">
                                     <input type="radio" name="food" value="1" id="rd1"><label for="rd1">자장면</label>
                                     <input type="radio" name="food" value="2" id="rd2"><label for="rd2">짬뽕</label>
                                     <input type="radio" name="food" value="3" id="rd3"><label for="rd3">볶음밥</label>
                                     <input type="radio" name="food" value="4" id="rd4"><label for="rd4">탕수육</label>
                                    </td>
                                </tr>


>> radio 버튼은 name을 같게 하면 같은 name들 중 하나만 선택이 가능하고
>> name을 다르게 하면 각자 선택이 가능해진다 (2개 그룹으로 묶으면 2종류의 배타적 선택이 가능)


@RequestMapping("reg")
@ResponseBody
public String reg(String title, String content, String category, String[] foods, String food) {
// System.out.println(category);
// for(String f : foods)
// System.out.println(f);
System.out.println(food);

return String.format("title:%s<br>content:%s<br>category:%s<br>" , title, content, category);
}


>> input의 value 값을 보낸다 (value 속성을 주지 않을 경우 on 이라는 문자열을 보냄)




< POST 입력 한글 입력이 깨지는 문제 >


-한글이 전달되는 것을 서버에서 받지 못하는 문제

title:ㅇㄴㅁㅇㄴㅁ…
content:어재서
category:1

이런식으로 출력됨

servlet만을 사용할 때의 request.setCharacterEncoding("UTF-8"); 을 설정해 줘야 한다
일일히 코드에 삽입해 주는 방법, 톰캣 인코딩 설정을 변경하는 방법 등이 있지만
servlet 필터를 사용해 만드는 것이 가장 효율적이고 문제가 생기지 않는다
(서블렛 필터는 로그인 권한 부여 보안 등에도 유용하게 사용 가능함)



UTF-8 인코딩용 필터 클레스 만들기

package com.newlecture.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {

@Override
public void doFilter(ServletRequest request
, ServletResponse response
, FilterChain chain)
throws IOException, ServletException {

request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);

}

}



web.xml에 필터 클레스 등록

 <filter>
   <filter-name>characterEncodingFilter</filter-name>
   <filter-class>com.newlecture.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
     <param-name>encoding</param-name>
     <param-value>UTF-8</param-value>
   </init-param>
   <init-param>
     <param-name>forceEncoding</param-name>
     <param-value>true</param-value>
   </init-param>
 </filter>
 <filter-mapping>
   <filter-name>characterEncodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>


한글 입력이 잘 되어 나오는지 확인






<SpringMVC 사용자 입력 5가지>


사용자로부터 전달되는 값

값의 종류

QueryString URL로 전달되는 문자열

POST 사용자의 입력으로 전달되는 문자열

Path 경로로 전달되는 문자열

Cookie 브라우저에 보관하고 있던 문자열

Header 요청 헤더로 전달되는 문자열





< QueryString 입력 방법 >


http://localhost:8080/customer/notice/list?p=1


HttpServletRequest로 받아서 쓰는 법
@RequestMapping("list")
public String list(HttpServletRequest request) throws ClassNotFoundException, SQLException {
String p = request.getParameter("p");
System.out.println(p);
return "notice.list";
}


더 쉽게 사용하는 법
@RequestMapping("list")
public String list(String p) throws ClassNotFoundException, SQLException {
System.out.println(p);
return "notice.list";
}





<QueryString 변수명과 기본값 처리>


변수명 변경
@RequestMapping("list")
public String list(@RequestParam("p") String page) throws ClassNotFoundException, SQLException {
System.out.println("page:"+page);
return "notice.list";
}

p prameter의 기본값이 없을 경우 400에러가 뜸 (Required String parameter 'p' is not present)
-페이지를 처음 로드할 때 등

http://localhost:8080/customer/notice/list


기본값 처리
@RequestMapping("list")
public String list(@RequestParam(name="p", defaultValue="1") int page) throws ClassNotFoundException, SQLException {
System.out.println("page:"+page);
return "notice.list";
}

전달하는 변수 타입을 int 로 해도 문제가 없다





< @RequestParam Optional 속성 >


참고 - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html


required 옵션의 기본값은 true
false로 설정하고 defaultValue를 안 줄 경우 변수타입에 따라 500 에러, 또는 null 값을 뱉어낸다
(참조변수형 매개변수에 param을 담을 경우 null 값이 올 수 있으므로 page는 출력되고 null값이 담긴다)
null 값을 처리하고 싶을 때 사용


value 옵션
name 옵션의 별칭이다 
둘다 같이 쓸 수는 없고 뭘 쓰든 결과는 같다
name과 value 쓰고 싶은 것을 사용하면 됨

+ Recent posts