개발하는 삶
[Spring] servlet 본문
Servlet
- 서버쪽에서 실행되면서 클라이언트의 요청에 따라 동적으로 서비스를 제공
- 독자적 실행x. 톰캣과 같은 서블릿 컨테이너에서 실행됨
- 톰캣 재실행 해야 하는 경우 (예시)
- web.xml 수정, 서블릿 매핑 수정 후엔 톰캣 재실행 해야 함
- 최초 요청시 init() 한번 실행
- 클라이언트 → 서블릿 요청 → init() → doget() ..
- 또 같은 서블릿을 요청시,
- 서블릿 요청 후 바로 → doget() ..따라서, 동일한 작업의 경우 서블릿을 재사용시 훨씬 효율적
- 핵심 기능
- 클라이언트로부터 요청을 받음 → 비즈니스 로직 처리
- → 결과값 클라이언트에 돌려주기
- 서블릿의 비즈니스 처리작업
- => 클라이언트로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것
- => 데이터베이스 연동 관련 작업
- => 다른 서버와 연동해서 데이터를 얻는 작업
HttpServlet
- doDelete(HttpServletRequest req, HttpServletResponse res)
- 서블릿이 DELETE 요청을 수행하기 위해 service() 를 통해 호출됨
- doGet(생략)
- 서블릿이 GET 요청을 수행하기 위해 service() 를 통해 호출됨
- doHead(생략)
- 서블릿이 HEAD 요청을 수행하기 위해 service() 를 통해 호출됨
- doPost(생략)
- 서블릿이 POST 요청을 수행하기 위해 service() 를 통해 호출됨
POST vs GET
- POST : 쿼리 파라미터 url 노출 X
- GET : 쿼리 파라미터 url 노출 O
생명주기 메서드
- init() : 서블릿 요청시 맨 처음 한번만 호출됨. 주로 서블릿 생성 시 초기화 작업
- doGet(), doPost() : 서블릿 요청시마다 매번 호출됨
- destory() : 서블릿이 기능을 수행하고 메모리에서 소멸될 때 호출됨
@WebServlet
- 서블릿 매핑 애너테이션
- 이 애너테이션이 붙은 클래스가 꼭 HttpServlet 을 상속 받아야함
<form> 태그 이용해 서블릿에 요청하기
- 예전엔 jsp가 없을 시절 html, css, js를 이용해 웹 프로그램을 만듬
- name : <form> 태그의 이름을 지정
- method : GET, POST. 데이터 전송 방법 (아무것도 지정하지 않으면 GET 자동지정)
- action : <form> 태그에서 데이터를 전송할 서블릿, JSP 지정(매핑이름)
- submit 을 지정하면 submit 현상이 일어났을 때 전송해줌
- encType : <form> 태그에서 전송할 데이터의 인코딩 타입
<form> 과 같이 쓰이는 HttpServletResponse 메서드
- getParameter(String name) : name 의 값을 알고있을 때 name 에 전송된 값을 받아오는데 사용
- getParameterNames() : name 값을 모를 때 사용
- getParameterValues(String name) : 같은 name 에 대해 여러개의 값을 얻을 때 사용
request.setCharacterEncoding("utf-8");
- UTF-8로 인코딩 요청해서 값을 받아옴 (한글로)
서블릿 MIME_TYPE
- 전송할 데이터의 종류 지정
- html로 전송시(대부분의 경우) : text/html
- 일반 텍스트로 전송시 : text/plain
- xml 데이터로 전송시 : application/xml
서블릿 생성시 맵핑법
여러개의 값을 전송할 때 요청 처리
- 하나의 name으로 여러 값을 서블릿으로 요청하는 법
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form name="frmLogin" method="get" action="login" encType="UTF-8">
아이디 : <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="checkbox" name="subject" value="java" >자바
<input type="checkbox" name="subject" value="C언어" >C언어
<input type="checkbox" name="subject" value="jSP" >JSP
<input type="checkbox" name="subject" value="안드로이드" >안드로이드
<input type="submit" value="로그인"> <input type="reset" value="다시입력">
</form>
</body>
</html>
package sec01.ex01;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8"); // 요청값 인코딩
String userId = request.getParameter("user_id");
String userPw = request.getParameter("user_pw");
System.out.println("아이디 : "+userId);
System.out.println("비밀번호 : "+userPw);
// name="subject" 인 애들 다 불러와 배열에 저장
String [] sub = request.getParameterValues("subject");
if (sub != null) { //null값(체크X) 말고 체크되어있는 값 가져오기
for(int i=0; i<sub.length; i++) {
System.out.println("선택과목 : "+sub[i]);
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
결과값
요청, 응답 동시에 처리
- 로그인
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
window.onload = function(){
let btn = document.querySelector("#btn");
btn.addEventListener("click", function(){
// name 값(frmLogin) 은 이렇게 써도 상관없음
let frmLogin = document.frmLogin;
let user_id = frmLogin.user_id.value;
let user_pw = frmLogin.user_pw.value;
// 공백 제거 했을때 0. 즉 아무것도 입력 안할시 경고!
if(user_id.trim().length == 0 || user_pw.trim().length == 0) {
alert("아이디와 비밀번호는 필수입니다.")
} else {
// form의 이름으로 바로 속성을 지정할 수 있음
frmLogin.method = "post";
frmLogin.action = "login5";
frmLogin.submit(); //js -> 서블릿으로 전송
}
});
}
</script>
</head>
<body>
<form name="frmLogin" method="get" action="3login" encType="UTF-8">
아이디 : <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="hidden" name="user_address" value="천안시">
<input type="button" id="btn" value="로그인">
</form>
</body>
</html>
package sec02.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/login3")
public class LoginServlet5 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 요청 인코딩
request.setCharacterEncoding("utf-8");
// 응답 인코딩
response.setContentType("text/html;charset=utf-8");
// PrintWriter : 자바 출력 스트림
PrintWriter out = response.getWriter();
String id = request.getParameter("user_id");
String pw = request.getParameter("user_pw");
String addr = request.getParameter("user_address");
// 응답 화면에 출력
out.println("<html>");
out.println("</html>");
out.println("<body>");
out.println(" 아이디 : "+ id);
out.println(" <br>");
out.println(" 비밀번호 : " + pw);
out.println(" <br>");
out.println(" 주소 : " + addr);
out.println(" <br>");
out.println("</body>");
out.println("</html>");
}
}
서블릿의 데이터베이스 연동
- 클라이언트
- → MemberServlet
- → MemberDAO (DB연동)
- → MemberVO (ArrayList)
PreparedStatement를 이용한 회원정보 실습
- Statement 를 이용해서 DB 연동시,
- 연동할 때마다 DBMS에서 다시 SQL문을 컴파일해야 하므로 속도가 느리다
- PreparedStatement 는 미리 SQL문을 컴파일해서 사용하므로 속도가 빠름
- 실행하려는 SQL문에 ? 를 넣을 수 있음
커넥션 풀
- 데이터베이스 연결에 시간을 줄이기 위해 사용
- 웹 애플리케이션이 실행됨과 동시에 연동할 DB와의 연결을 미리 설정해둠
- 필요할때마다 커넥션풀 객체의 메서드를 호출함
JNDI
- 웹 애플리케이션 실행시 톰캣이 만들어놓은 커넥션풀 객체에 접근할때 이용
- 필요한 자원을 키/값 쌍으로 저장한 후
- 필요할 때 키를 이용해 값을 얻는 방법
회원정보 만들기
- executeQuery : 수행결과로 ResultSet 객체의 값을 반환
- executeUpdate : 수행결과로 Int 타입의 값을 반환.
- SELECT 구문을 제외한 다른 구문을 수행할 때 사용되는 함수 (INSERT / DELETE / UPDATE)
// 오라클 DB
// 테이블 입력
create table t_member(
id varchar(10) primary key,
pwd varchar(10),
name varchar(50),
email varchar(50),
// 테이블의 요소들 생성한 시간 부여
joinDate date default sysdate
);
// 테이블에 요소 추가
// sysdate : 현재 시간 (요소 추가한 시간)
insert into t_member
values('hong', '1212', '홍길동', 'hong@gmail.com', sysdate);
insert into t_member
values('lee', '1212', '이순신', 'lee@test.com', sysdate);
insert into t_member
values('kim', '1212', '김유신', 'kim@jweb.com', sysdate);
commit;
SELECT * FROM t_member;
// MemberVO.java
// DB 값 저장
package sec01.ex01;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
// MemberServlet.java
package sec01.ex01;
// member 에 접속하면 실행하라
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 응답할 문장 html, utf-8 형식으로
res.setContentType("text/html;charset=utf-8");
// SQL문으로 조회할 MemberDAO 객체를 생성
MemberDAO dao = new MemberDAO();
// 응답할거 (html로 출력)
PrintWriter out = res.getWriter();
// DAO의 listMembers() 메서드로 회원정보를 조회해 담음
List<MemberVO> list = dao.listMembers();
// 표로 출력하기 (header 부분)
out.print("<html><body>");
out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td></tr>");
// 조회한 회원정보를 for문과 <tr>태그를 이용해 리스트로 출력
for(int i=1; i<list.size(); i++) {
MemberVO memberVO = list.get(i);
String id = memberVO.getId();
String pwd = memberVO.getPwd();
String name = memberVO.getName();
String email = memberVO.getEmail();
Date joinDate = memberVO.getJoinDate();
out.print("<tr><td>"+id+"</td><td>"+pwd+"</td><td>"
+name+"</td><td>"+email+"</td><td>"+joinDate+"</td>");
}
out.println("</table></body></html>");
}
}
// MemberDAO.java
package sec01.ex01;
public class MemberDAO {
// DB 접속 정보 불러오기
// 드라이버 이름, JDBC 연결, 접속아이디, 비밀번호
private String driver = "oracle.jdbc.driver.OracleDriver";
private String url = "jdbc:oracle:thin:@todair.synology.me:51521:xe";
private String user = "scott2_20";
private String pwd = "tiger";
// JDBC 관련 클래스들
// Statement : SQL문을 실행하는 인터페이스(실행 객체 생성)
// Connection : DB와 연결성을 갖는 인터페이스(DB서버 연결)
private Statement stmt;
private Connection con;
// 사용자 정보들을 모을 List 객체 만들기
public List<MemberVO> listMembers () {
List<MemberVO> list = new ArrayList<MemberVO>();
try {
// 데이터베이스 연결
// DB자원은 Connection(DB서버 연결) -> Statement(SQL문 생성)
// -> ResultSet(결과객체 생성)
connDB();
// 회원정보 조회할 SQL 문
String query = "select * from t_member";
// PreparedStatement : Statement 클래스의 기능 향상 버전
// 비슷한 SQL 문을 반복적으로 실행할 때 보다 효율적으로 사용하기 위함
// Pre...이건 재사용성이 높고 효율적임 (sta..보다)
// SQL 문을 이용해 회원정보를 조회함 (con을 통해)
PreparedStatement pstmt = con.prepareStatement(query);
// ResultSet : 조회된 결과 데이터를 갖는 인터페이스
ResultSet rs = pstmt.executeQuery();
// 데이터 다 꺼내기
// rs.next() : boolean 값 리턴. (행 반환시 true (행의갯수 2개이상))
while (rs.next()) {
// 각 컬럼 값 받아옴
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
// 각 컬럼값을 다시 MemberVO 객체의 속성에 설정
MemberVO vo = new MemberVO();
vo.setId(id);
vo.setPwd(pwd);
vo.setName(name);
vo.setEmail(email);
vo.setJoinDate(joinDate);
// 설정된 MemberVO 객체를 다시 ArrayList에 저장함
// 행이 계속 쌓임
list.add(vo);
}
// 연결을 끊음
// 연결 끊는 순서는 역순으로 하면 됨
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
//예외 설정
e.printStackTrace();
}
// 조회된 레코드의 개수만큼 MemberVO 객체를 저장한 ArrayList를 반환함
return list;
}
// 드라이버 실행 (데이터베이스 연결)
private void connDB() {
try {
// driver 로드하는 class를 생성 (new 한것과 같음)
Class.forName(driver);
System.out.println("Oracle driver 로딩 성공");
// DB 접속
// DriverManager 는 JDBC 드라이버를 통해 url, user, pwd 연결시켜줌
con = DriverManager.getConnection(url, user, pwd);
System.out.println("Connection 생성 성공");
// SQL 실행할 수있는 변수 생성
stmt = con.createStatement();
System.out.println("Statement 생성 성공");
} catch(Exception e) {
e.printStackTrace();
}
}
}
DataSource 이용해 회원정보 등록/삭제
- 회원가입, 로그인/삭제 구현
테이블 정보
파일 정보
Servers - context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- 이클립스에 톰캣 DataSource 설정 -->
<!--
name = jdbc/sql프로그램명 : 데이터소스에 대한 JNDI 이름
auth = 인증주체 (톰캣이 컨테이너라서 container)
type = 리턴타입
maxActive = 최대 연결이 가능한 컬렉션 수
maxWait = 새로운 연결이 생길 때까지 기다릴수있는 최대 시간
(-1 이면 기다리지 않는다는 뜻)
dirver~password : 데이터베이스를 연결하는 데 필요한 네가지 값 설정
-->
<Resource
name = "jdbc/oracle"
auth = "Container"
type = "javax.sql.DataSource"
driverClassName = "oracle.jdbc.OracleDriver"
url = "jdbc:oracle:thin:@todair.synology.me:51521:XE"
username = "scott2_20"
password = "tiger"
maxActive = "50"
maxWait = "-1" />
</Context>
memberForm.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<script type="text/javascript">
function fn_sendMember(){
//form 객체 변수에 저장
var frmMember=document.frmMember;
// id, pwd, name, email 값들 저장
var id=frmMember.id.value;
var pwd=frmMember.pwd.value;
var name=frmMember.name.value;
var email=frmMember.email.value;
// 입력 여부 검사
if(id.length==0 ||id==""){
alert("아이디는 필수입니다.");
}else if(pwd.length==0 ||pwd==""){
alert("비밀번호는 필수입니다.");
}
else if(name.length==0 ||name==""){
alert("이름은 필수입니다.");
}else if(email.length==0 ||email==""){
alert("이메일은 필수입니다.");
}else{
// submit 구현
frmMember.method="post";
frmMember.action="member3";
frmMember.submit();
}
}
</script>
</head>
<body>
<form name="frmMember">
<table>
<th>회 원 가 입</th>
<tr>
<td>아이디</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="text" name="pwd"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>이메일</td>
<td><input type="text" name="email"></td>
</tr>
</table>
// 버튼 창
<input type="button" value="가입하기" onclick="fn_sendMember()">
<input type="reset" value="다시 입력">
<input type="hidden" name="command" value="addMember" />
</form>
</body>
</html>
MemberVO.java
package sec02.ex01;
import java.sql.Date;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
MemberDAO.java
package sec02.ex01;
public class MemberDAO {
// 아래는 여기에 안써도 됨. servers의 context.xml에 적었으니
// private static final String driver = "oracle.jdbc.driver.OracleDriver";
// private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
// private static final String user = "scott";
// private static final String pwd = "tiger";
private Connection con;
private PreparedStatement pstmt;
// DB와 관련된 커넥션 정보를 담음. 빈에 등록/주입함
// DataSource 이용해 DB 연동 (커넥션풀 객체를 구현할때 쓰는 것)
private DataSource dataFactory;
public MemberDAO() {
try {
// JNDI : 외부에서 객체를 가져올 때 쓰는 기술
// Context : JNDI 사용과 관련됨. 명명 객체.
// InitialContext : 이름 지정 작업을 수행하기 위한 시작 컨테스트
Context ctx = new InitialContext();
// lookup : 명명된 객체를 검색함
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataFactory = (DataSource) envContext.lookup("jdbc/oracle");
} catch (Exception e) {
e.printStackTrace();
}
}
public List<MemberVO> listMembers() {
List<MemberVO> list = new ArrayList<MemberVO>();
try {
// connDB();
con = dataFactory.getConnection(); // 커넥션 풀
String query = "select* from t_member";
System.out.println(query);
pstmt = con.prepareStatement(query);
ResultSet rs = pstmt.executeQuery(query);
while(rs.next()) {
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
MemberVO vo = new MemberVO();
vo.setId(id);
vo.setPwd(pwd);
vo.setName(name);
vo.setEmail(email);
vo.setJoinDate(joinDate);
list.add(vo);
}
rs.close();
pstmt.close();
con.close();
}catch (Exception e) {
e.printStackTrace();
}
return list;
}
public void addMember(MemberVO memberVO) {
try {
Connection con = dataFactory.getConnection();
String id = memberVO.getId();
String pwd = memberVO.getPwd();
String name = memberVO.getName();
String email = memberVO.getEmail();
String query = "insert into t_member";
query += "(id, pwd, name, email)";
query += " values(?, ?, ?, ?)";
System.out.println("query=" + query);
pstmt = con.prepareStatement(query);
pstmt.setString(1, id);
pstmt.setString(2, pwd);
pstmt.setString(3, name);
pstmt.setString(4, email);
pstmt.executeUpdate();
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void delMember(String id)
{
try
{
con = dataFactory.getConnection();
String query = "delete from t_member" + " where id=?"; // delete 문을 문자열로 생성
System.out.println("preparedStatement: " + query);
pstmt = con.prepareStatement(query);
pstmt.setString(1, id); // 매개변수가 id 달랑 하나니까 바로 사용이 됨!
pstmt.executeUpdate();
pstmt.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
/*
private void connDB() {
try {
Class.forName(driver);
System.out.println("Oracle 드라이버 로딩 성공");
con = DriverManager.getConnection(url, user, pwd);
System.out.println("Connection 생성 성공");
pstmt = (PreparedStatement) con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}
MemberServlet.java
package sec02.ex01;
@WebServlet("/member3")
public class MemberServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
protected void doHandle(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MemberDAO dao = new MemberDAO(); // SQL문으로 조회할 MemberDAO 객체 생성
PrintWriter out = response.getWriter();
// command 값(<hidden> 태그에서 넘겨준 값)을 받아옴
String command = request.getParameter("command");
// 회원 가입창에서 전송된 command가 addMember이면 전송된 값들을 받아옴
if (command != null && command.equals("addMember"))
{
// 회원 가입창에서 전송된 값들을 얻어와 MemberVO 객체에 저장 후 SQL문을 이용해 전달
String _id = request.getParameter("id");
String _pwd = request.getParameter("pwd");
String _name = request.getParameter("name");
String _email = request.getParameter("email");
MemberVO vo = new MemberVO();
vo.setId(_id);
vo.setPwd(_pwd);
vo.setName(_name);
vo.setEmail(_email);
dao.addMember(vo);
} else if (command != null && command.contentEquals("delMember"))
{
String id = request.getParameter("id");
dao.delMember(id); // 주석 해제
}
List<MemberVO> list = dao.listMembers(); // listMembers() 메서드로 회원 정보 조회
out.print("<html><body>");
out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td><td>삭제</td></tr>");
for (int i = 0; i < list.size(); i++)
{
// 조회한 회원 정보를 for과 <tr> 태그를 이용해 리스트로 출력
MemberVO memberVO = (MemberVO) list.get(i);
String id = memberVO.getId();
String pwd = memberVO.getPwd();
String name = memberVO.getName();
String email = memberVO.getEmail();
Date joinDate = memberVO.getJoinDate();
out.print("<tr><td>" + id + "</td><td>"
+ pwd + "</td><td>" + name + "</td><td>"
+ email + "</td><td>" + joinDate + "</td><td>"
+ "<a href='/member3?command=delMember&id=" + id + "'> 삭제 </a></td><tr>" );
}
out.print("</table>");
out.print("<a herf='/pro07/memberForm.html'>새 회원 가입하기</a></body></html>");
}
}
'Spring' 카테고리의 다른 글
[Spring] 쿠키, 세션, ajax (0) | 2022.08.25 |
---|---|
[Spring] 스프링과 서블릿, 바인딩 (0) | 2022.08.24 |
[Spring] 로그인, 스프링 시큐리티 (0) | 2022.08.18 |
[Spring] HTTP 요청/응답 (0) | 2022.07.23 |
[Spring] 스프링 MVC (0) | 2022.07.20 |