JavaWeb项目中用Servlet实现学生签到和下载文件功能,过程中遇到了一些路径上的问题,做个总结。
目录结构:
学生签到实验(将从前端收到的学生签到信息记录在指定文件中,向login.txt中记录学生签到信息):
1、多次试验发现,用相对路径(String path="/login.txt")可以找到文件,但是写不进去内容;
2、用String path=this.getServletContext().getRealPath("/login.txt")方法获取绝对路径,可以写入,但是内容是记录在部署目录中,原因如下:
输出this.getServletContext().getRealPath("/login.txt")(或去掉斜杠)语句,得到:
D:\myapps\my-ideaworksapce\JavaWebProject\out\artifacts\testServlet_war_exploded\StudentLoginServlet
可以看到,绝对路径被定位到了部署路径中。因为tomcat上运行的项目是编译、部署完成的项目
3、指定绝对路径D:\myapps\my-ideaworkspace\JavaWebProject\web\login.txt,可以在该目录下的文件中写入内容,而且部署路径out/artifacts/testServlet_war_exploded/WEB-INF/classes/login.txt会与之同步
4、tomcat重启时会重新部署目录,因此之前的记录信息在tomcat重启后会不复存在
5、在web中的反斜杠 /
① 和网页跳转相关的'/'代表从服务器根路径(locallost:8080/)开始定位
比如<a href=’/JavaWebProject/index.jsp’>跳转</a>
再比如重定向中的response.sendRedirect("/JavaWebProject/index.jsp");
注:请求转发的跳转页面是从项目根路径开始寻找的request.getRequestDispatcher("/index.jsp").forward(request, response);因为请求转发相当于已经在当前项目中的网页,现在要跳转到该项目中的另一个网页,所以是从当前项目的根目录寻找要跳转的页面。请求转发和重定向的区别需要清楚。
② java中的'/'代表从项目部署后的项目根路径(localhost:8080//JavaWebProject)开始定位
下载文件实验:
①
InputStream fin=this.getServletContext().getResourceAsStream("/downloads/" +filename);//成功!
②
InputStream fin=new FileInputStream("/downloads/"+filename);//不起作用!
第一条语句可以将downloads中的文件作为字节流输出,并通过设置消息头提供下载功能,而二条语句却没有作用(无法在浏览器下载内容)。联系前面的实验结果“用相对路径(String path="/login.txt")可以找到文件,但是写不进去内容”。推测:Web项目无法直接通过相对路径进行流的操作
代码:
学生签到实验:
@WebServlet(urlPatterns = "/StudentLoginServlet" )
public class StudentLoginServlet extends HttpServlet {//直接继承Servlet类的话,this.getServletConfig.getServletContext.getRealPath()似乎有点问题
PrintWriter fout=null;//输出流,用于将从前端收到的学生签到信息记录在指定文件中。全局变量,供整个对象使用
ArrayList<String> idCheck=new ArrayList<>();//记录历史签到id
ArrayList<String> ipCheck=new ArrayList<>();//记录历史签到ip
@Override
public void init() throws ServletException {
String path="/login.txt";//文件路径
File file=new File(this.getServletContext().getRealPath(path));
try {
fout=new PrintWriter(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取表单数据
String stuId=req.getParameter("stuId");
String stuName=req.getParameter("stuName");
String stuAge=req.getParameter("stuAge");
//获取客户端的IP地址、签到时间
String IP=req.getRemoteAddr();
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String loginTime=format.format(new Date());
//将登陆信息记录到日志文件中
int index1=0;//判定id是否重复,0代表不重复,1代表重复
int index2=0;//判定ip是否重复,0代表不重复,1代表重复
if(fout!=null){
synchronized (this){
if(!idCheck.contains(stuId)&&!ipCheck.contains(IP)){
idCheck.add(stuId);
ipCheck.add(IP);
fout.println("学号为:"+stuId+",姓名是:"+stuName+",年龄是:"+stuAge+",IP地址为:"+IP+",签到时间为:"+loginTime);
fout.flush();
}else if(idCheck.contains((stuId))){
index1=1;
}else if(ipCheck.contains(IP)){
index2=1;
}
}
}
PrintWriter out=resp.getWriter();
if(index1==0&&index2==0){
out.println("签到成功!");
}else if(index1==1){
out.println("请勿重复签到!");
}else{
out.println("同一台机器只能签到一名同学!");
}
}
@Override
public void destroy() {
if(fout!=null){
fout.close();
}
}
}
下载文件实验:
public class ContextDownloadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置相应头信息
String filename=req.getParameter("filename");//接收文件名
resp.setHeader("Content-Disposition","attachment;filename="+filename);
//获取绝对路径
String realpath=this.getServletContext().getRealPath("/downloads/" +filename);
System.out.println(realpath);
//发送文件
InputStream fin=this.getServletContext().getResourceAsStream("/downloads/" +filename);//成功!
// InputStream fin=new FileInputStream("/downloads/"+filename);//不起作用!
OutputStream out=resp.getOutputStream();
byte[] buff=new byte[1024];
int len=-1;
while ((len=fin.read(buff))!=-1){
out.write(buff,0,len);
}
fin.close();
out.close();
}
}