15. 파일 첨부
* 라이브러리 등록 및 파일 upload /download 테스트
* WEB-INF밑에 upload폴더 생성. ( 파일 저장 폴더, 이클립스에서 생성. )
: 이클립스 개발 시 실제 파일이 upload되는 경로는 따로 있다
해당 workspace 경로밑에
\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0
\wtpwebapps\day06_fileupload\upload
에 파일이 저장되어 있다.
<< 설정 >>
* http://servlets.com/cos/ 사이트 이동
* 파일 업로드 라이브러리. (cos 사용 )
- servlet software
- Download the package
- cos-26Dec2008.zip 다운.
* lib/cos.jar파일을 WEB-INF/lib/cos.jar로 복사.
* upload시 동일한 이름의 파일이 존재하면 파일명 뒤에 숫자가 붙는다.
예를 들어 a.jpg가 존재하면 a.jpg, a(1).jpg,.. 이런식으로 증가된다. 실제 저장되는 파일명과 사용자가 올린 파일명 2개가 존재한다.
* enctype="multipart/form-data"으로 전송.
* 받을때도 MultipartRequest mr=new MultipartRequest (...)로 받아 사용한다.
파일업로드 테스트
[[ 테이블 ]]
; 원본 파일명 - 사용자가 올린 파일명.
; 실제저장된 파일명 - 서버에 저장된 파일명.
create table fileinfo(
filenum number primary key,--파일고유번호
writer varchar2(20),--작성자
title varchar2(20),--제목
content varchar2(50),--내용
orgfilename varchar2(100),--원본파일명
savefilename varchar2(100),--실제저장된파일명
filesize number -- 파일크기
);
create sequence fileinfo_seq;
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>day06_dbcp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- dbcp 설정 -->
<resource-ref>
<description>Oracle Datasource example</description>
<res-ref-name>jdbc/myoracle</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
META-INF > context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:xe"
username="scott" password="tiger" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
</Context>
[[ main.html ]]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<a href="file1/fileupload.jsp">파일업로드하기</a><br/>
<a href="file1/filelist.jsp">파일목록보기</a>
</body>
</html>
[[ fileupload.jsp ]]
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="fileuploadOk.jsp" enctype="multipart/form-data">
<table border="1" width="500">
<tr>
<td>작성자</td>
<td><input type="text" name="writer"/></td>
</tr>
<tr>
<td>제목</td>
<td><input type="text" name="title"/></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="5" cols="50" name="content"></textarea></td>
</tr>
<tr>
<td>첨부파일</td>
<td><input type="file" name="file1"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="전송"/>
<input type="reset" value="취소"/>
</td>
</tr>
</table>
</form>
</body>
</html>
[[ fileuploadOk.jsp ]]
;
public MultipartRequest(javax.servlet.http.HttpServletRequest request,
java.lang.String saveDirectory,
int maxPostSize,
java.lang.String encoding,
FileRenamePolicy policy)
throws java.io.IOException
<%@page import="test.file.FileinfoDao"%>
<%@page import="java.io.File"%>
<%@page import="test.file.FileinfoVo"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
//upload폴더의 실제경로를 얻어옴
String dir=application.getRealPath("/upload");
MultipartRequest mr=new MultipartRequest(
request,//request객체
dir,//파일을 저장할 폴더
1024*1024*5, //최대 업로드크기 설정(5MB설정)
"euc-kr",//인코딩방식
new DefaultFileRenamePolicy()//동일한파일명이 존재하면 파일명뒤에 일련번호 부여해서파일생성
);
//request객체가 아닌 MultipartRequest객체로 파라미터 읽어와야 함!!!
String writer=mr.getParameter("writer");
String title=mr.getParameter("title");
String content=mr.getParameter("content");
//전송된 파일명 읽어오기
String orgfilename=mr.getOriginalFileName("file1");
//실제저장된 파일명 읽어오기
String savefilename=mr.getFilesystemName("file1");
//////////// 전송된 정보를 DB에 저장하기 ////////////////
//전송된 파일크기 구하기
File f=new File(dir + File.separator + savefilename);
long filesize=f.length();
//전송된 정보를 vo에 담기
FileinfoVo vo=new FileinfoVo(0,writer,title,content,
orgfilename,
savefilename,
filesize);
//DB에 데이터 추가하기
FileinfoDao dao=new FileinfoDao();
int n=dao.insert(vo);
if(n>0){
out.println(" 데이터 전송 성공!<br/>");
}else{
out.println(" 데이터 전송 실패!<br/>");
}
%>
작성자 :<%=writer %><br/>
제목 :<%= title %><br/>
내용 : <%=content %><br/>
전송된 파일명:<%=orgfilename %><br/>
실제저장된 파일명:<%=savefilename %><br/>
</body>
</html>
Table >
[[ filelist.jsp ]]
; <jsp:useBean id="빈이름" class="자바빈 클래스" scope="사용범위" />
scope : request, page, session, application, 기본값은 page
<%@page import="java.util.ArrayList"%>
<%@page import="test.file.FileinfoVo"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<jsp:useBean id="dao" class="test.file.FileinfoDao"/>
<table border="1" width="600">
<caption><h2>파일목록</h2></caption>
<tr>
<th>작성자</th>
<th>제목</th>
<th>파일명</th>
<th>파일크기</th>
<th>다운로드</th>
<th>삭제</th>
</tr>
<%
ArrayList<FileinfoVo> list = dao.getList();
for(int i=0;i<list.size();i++){
FileinfoVo vo = list.get(i);
%>
<tr>
<td><%=vo.getWriter() %></td>
<td><%=vo.getTitle() %></td>
<td><%=vo.getOrgfilename() %></td>
<td><%=vo.getFilesize() %></td>
<td><a href="filedownload.jsp?filenum=<%=vo.getFilenum() %>">다운로드</a></td>
<td><a href="filedelete.jsp?filenum=<%=vo.getFilenum() %>">삭제</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
[[ filedelete.jsp ]]
; 파일 삭제
<%@page import="java.io.File"%>
<%@page import="test.file.FileinfoVo"%>
<%@page import="test.file.FileinfoDao"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
////////// 1. 파일 삭제 하기 //////////////////////
int filenum=Integer.parseInt(request.getParameter("filenum"));
FileinfoDao dao=new FileinfoDao();
FileinfoVo vo=dao.getInfo(filenum);
//실제저장된 파일명 얻어오기
String savefilename=vo.getSavefilename();
//upload폴더의 실제 경로 얻어오기
String dir=application.getRealPath("/upload");
//삭제할 파일정보를 갖는 File객체 생성
File f=new File(dir+File.separator+savefilename);
if(!f.delete()){
out.println("삭제 오류!");
}
///////// 2. DB에서 파일정보 삭제하기 ////////////////
int n=dao.delete(filenum);
if(n>0){
out.println("삭제성공!");
}else{
out.println("삭제 오류!");
}
%>
</body>
</html>
[[ filedownload.jsp ]]
<%@page import="java.io.File"%>
<%@page import="java.io.OutputStream"%>
<%@page import="java.io.BufferedInputStream"%>
<%@page import="java.io.BufferedOutputStream"%>
<%@page import="java.io.FileInputStream"%>
<%@page import="test.file.FileinfoDao"%>
<%@page import="test.file.FileinfoVo"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%
//파일번호얻어오기
int filenum = Integer.parseInt(request.getParameter("filenum"));
//파일에 대한 정보를 db에서 얻어오기.
FileinfoDao dao = new FileinfoDao();
FileinfoVo vo = dao.getInfo(filenum);
String savefilename=vo.getSavefilename();
String orgfilename=vo.getOrgfilename();
long filesize = vo.getFilesize();
// 다운로드 창 설정(한글파일명이 깨지지 않도록)----------------------------------
// euc-kr로 변환한 파일명 만들기
String filename=new String(orgfilename.getBytes("euc-kr"),"8859_1");
//다운로드창으로 응답하기
response.setContentType("application/octet-stream");
//파일크기 설정하기
response.setContentLength((int)filesize);
//다운로드창에 보일 파일명(euc-kr로 변환된) 설정하기
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
// 실제로 다운로드(클라이언트에 복사) 하기 --------------------------------------
OutputStream os = response.getOutputStream();
//파일이 저정된 경로 얻어오기
String dir=application.getRealPath("/upload");
//서버에 저장된 파일을 얻어오기 위한 스트림 객체
FileInputStream fis = new FileInputStream( dir + File.separator + savefilename );
//성능향상을 위해 버퍼기능을 갖는 스트림객체로 반환하기
BufferedOutputStream bos = new BufferedOutputStream(os);
BufferedInputStream bis = new BufferedInputStream(fis);
//서버의 파일을 클라이언트에 복사하기
int n=0;
byte[] b=new byte[1024];
while((n=bis.read(b))!=-1){
bos.write(b, 0, n);
}
bis.close();
bos.close();
%>
** Filedownload.jsp 파일을 Servlet으로 사용해도 된다.
[[ FiledownloadServlet.java ]]
package test.file;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FiledownloadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//파일번호얻어오기
int filenum = Integer.parseInt(request.getParameter("filenum"));
//파일에 대한 정보를 db에서 얻어오기.
FileinfoDao dao = new FileinfoDao();
FileinfoVo vo = dao.getInfo(filenum);
String savefilename=vo.getSavefilename();
String orgfilename=vo.getOrgfilename();
long filesize = vo.getFilesize();
// 다운로드 창 설정(한글파일명이 깨지지 않도록)----------------------------------
// euc-kr로 변환한 파일명 만들기
String filename=new String(orgfilename.getBytes("euc-kr"),"8859_1");
//다운로드창으로 응답하기
response.setContentType("application/octet-stream");
//파일크기 설정하기
response.setContentLength((int)filesize);
//다운로드창에 보일 파일명(euc-kr로 변환된) 설정하기
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
// 실제로 다운로드(클라이언트에 복사) 하기 --------------------------------------
OutputStream os = response.getOutputStream();
//파일이 저정된 경로 얻어오기
String dir= getServletContext().getRealPath("/upload"); //application.getRealPath("/upload");
//서버에 저장된 파일을 얻어오기 위한 스트림 객체
FileInputStream fis = new FileInputStream( dir + File.separator + savefilename );
//성능향상을 위해 버퍼기능을 갖는 스트림객체로 반환하기
BufferedOutputStream bos = new BufferedOutputStream(os);
BufferedInputStream bis = new BufferedInputStream(fis);
//서버의 파일을 클라이언트에 복사하기
int n=0;
byte[] b=new byte[1024];
while((n=bis.read(b))!=-1){
bos.write(b, 0, n);
}
bis.close();
bos.close();
}
}
[[ DbcpBean.java ]]
package test.dbcp;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DbcpBean {
private DataSource ds;
public DbcpBean(){
try{
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
ds = (DataSource)envContext.lookup("jdbc/myoracle");
}catch(NamingException ne){
System.out.println(ne.getMessage());
}
}
public Connection getCon(){
Connection con = null;
try{
con = ds.getConnection();
return con;
}catch(SQLException se){
System.out.println(se.getMessage());
return null;
}
}
}
[[ FileinfoVo ]]
package test.file;
public class FileinfoVo {
private int filenum;
private String writer ;
private String title ;
private String content ;
private String orgfilename ;
private String savefilename ;
private long filesize;
public FileinfoVo(){}
public FileinfoVo(int filenum, String writer, String title, String content,
String orgfilename, String savefilename, long filesize) {
super();
this.filenum = filenum;
this.writer = writer;
this.title = title;
this.content = content;
this.orgfilename = orgfilename;
this.savefilename = savefilename;
this.filesize = filesize;
}
public int getFilenum() {
return filenum;
}
public void setFilenum(int filenum) {
this.filenum = filenum;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getOrgfilename() {
return orgfilename;
}
public void setOrgfilename(String orgfilename) {
this.orgfilename = orgfilename;
}
public String getSavefilename() {
return savefilename;
}
public void setSavefilename(String savefilename) {
this.savefilename = savefilename;
}
public long getFilesize() {
return filesize;
}
public void setFilesize(long filesize) {
this.filesize = filesize;
}
}
[[ FileInfoDao.java ]]
package test.file;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import test.dbcp.DbcpBean;
public class FileinfoDao {
private DbcpBean dbcp;
public FileinfoDao() {
dbcp=new DbcpBean();
}
public int delete(int filenum){
Connection con=null;
PreparedStatement pstmt=null;
try{
con=dbcp.getCon();
String sql="delete from fileinfo where filenum=?";
pstmt=con.prepareStatement(sql);
pstmt.setInt(1,filenum);
int n=pstmt.executeUpdate();
return n;
}catch(SQLException se){
System.out.println(se.getMessage());
return -1;
}finally{
try{
if(pstmt!=null) pstmt.close();
if(con!=null) con.close();
}catch(SQLException se){}
}
}
//파일번호에 해당하는 파일정보 반환하는 메소드
public FileinfoVo getInfo(int filenum){
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
con=dbcp.getCon();
String sql="select * from fileinfo where filenum=?";
pstmt=con.prepareStatement(sql);
pstmt.setInt(1,filenum);
rs=pstmt.executeQuery();
if(rs.next()){
FileinfoVo vo=new FileinfoVo(
rs.getInt("filenum"),
rs.getString("writer"),
rs.getString("title"),
rs.getString("content"),
rs.getString("orgfilename"),
rs.getString("savefilename"),
rs.getLong("filesize"));
return vo;
}
return null;
}catch(SQLException se){
System.out.println(se.getMessage());
return null;
}finally{
try{
if(rs!=null) rs.close();
if(pstmt!=null) pstmt.close();
if(con!=null) con.close();
}catch(SQLException se){}
}
}
public ArrayList<FileinfoVo> getList(){
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
con=dbcp.getCon();
String sql="select * from fileinfo order by filenum desc";
pstmt=con.prepareStatement(sql);
rs=pstmt.executeQuery();
ArrayList<FileinfoVo> list=new ArrayList<>();
while(rs.next()){
FileinfoVo vo=new FileinfoVo(
rs.getInt("filenum"),
rs.getString("writer"),
rs.getString("title"),
rs.getString("content"),
rs.getString("orgfilename"),
rs.getString("savefilename"),
rs.getLong("filesize"));
list.add(vo);
}
return list;
}catch(SQLException se){
System.out.println(se.getMessage());
return null;
}finally{
try{
if(rs!=null) rs.close();
if(pstmt!=null)pstmt.close();
if(con!=null) con.close();
}catch(SQLException se){}
}
}
public int insert(FileinfoVo vo){
Connection con=null;
PreparedStatement pstmt=null;
String sql="insert into fileinfo " +
"values(fileinfo_seq.nextval,?,?,?,?,?,?)";
try{
con=dbcp.getCon();//dbcp에서 컨넥션 객체 얻어오기
pstmt=con.prepareStatement(sql);
//?에 대응되는 값 설정하기
pstmt.setString(1,vo.getWriter());
pstmt.setString(2,vo.getTitle());
pstmt.setString(3,vo.getContent());
pstmt.setString(4,vo.getOrgfilename());
pstmt.setString(5,vo.getSavefilename());
pstmt.setLong(6,vo.getFilesize());
int n=pstmt.executeUpdate();
return n;
}catch(SQLException se){
System.out.println(se.getMessage());
return -1;
}finally{
try{
if(pstmt!=null) pstmt.close();
if(con!=null) con.close();
}catch(SQLException se){}
}
}
}
EX> 파일여러개 upload
fileupload.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
request.setCharacterEncoding("euc-kr");
String cnt=request.getParameter("cnt");
int icnt=0;
if(cnt!=null){
icnt=Integer.parseInt(cnt);
}
String writer=request.getParameter("writer");
String title=request.getParameter("title");
String content=request.getParameter("content");
if(writer==null) writer="";
if(title==null) title="";
if(content==null) content="";
%>
<form method="post" action="fileupload.jsp">
<table border="1" width="500">
<tr>
<td>작성자</td>
<td><input type="text" name="writer" value="<%=writer %>"/></td>
</tr>
<tr>
<td>제목</td>
<td><input type="text" name="title" value="<%=title %>"/></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="5" cols="50" name="content"><%=content %></textarea></td>
</tr>
<tr>
<td>첨부파일갯수</td>
<td><input type="text" name="cnt" value="<%=cnt %>"/>
<input type="submit" value="확인"/>
</td>
</tr>
</table>
</form>
<form method="post" action="fileuploadOk.jsp" enctype="multipart/form-data">
<input type="hidden" name="writer" value="<%=writer %>"/>
<input type="hidden" name="title" value="<%=title %>"/>
<input type="hidden" name="content" value="<%=content %>"/>
<table border="1" width="500">
<%
for(int i=0;i<icnt;i++){
%>
<tr>
<td>첨부파일<%=i+1 %></td>
<td><input type="file" name="file<%=i%>"></td>
</tr>
<%
}
%>
<tr>
<td colspan="2" align="center">
<input type="submit" value="전송"/>
</td>
</tr>
</table>
</form>
</body>
</html>
fileuploadOk.jsp
<%@page import="java.util.Enumeration"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
String dir=application.getRealPath("/upload");
MultipartRequest mr = new MultipartRequest(
request,
dir,
1024*1024*5,
"euc-kr",
new DefaultFileRenamePolicy()
);
String writer = mr.getParameter("writer");
String title = mr.getParameter("title");
String content=mr.getParameter("content");
%>
작성자:<%=writer %><br/>
제목:<%=title %><br/>
내용:<%=content %><br/>
<%
//전송된 파일명을 얻어옴.
Enumeration<String> em=mr.getFileNames();
while(em.hasMoreElements()){
//전송된 file의 name속성(파라미터이름) 얻어오기
String fileName=em.nextElement();
//전송된 파일의 원본파일명 얻어오기;
String orgfilename=mr.getOriginalFileName(fileName);
//실제로 저장된 파일명 얻어오기
String savefileString=mr.getFilesystemName(fileName);
%>
전송된 파일명:<%=orgfilename %><br/>
저장된 파일명:<%=savefileString %><br/>
<%
}
%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>Insert title here <% request.setCharacterEncoding("euc-kr"); String cnt=request.getParameter("cnt"); int icnt=0; if(cnt!=null){ icnt=Integer.parseInt(cnt); } String writer=request.getParameter("writer"); String title=request.getParameter("title"); String content=request.getParameter("content"); if(writer==null) writer=""; if(title==null) title=""; if(content==null) content=""; %>