200 OK //客户端请求成功
400 Bad Request //客户端请求语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态码必须和www-Authentication报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝服务
404 Not Found //请求资源不存在,输入url错误
500 Internal Service Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
tomca真正访问的是项目目录下out里面部署的文本项目,目录下的资源对应的是项目目录的资源
#解决tomcat,startup.bat运行闪退方法右键startup.bat进入编辑在最顶端加上2个路径
SET JAVA_HOME=() #java目录
SET CATALINA_HOME=() #tomcat目录
#控制台可以CATALINA_BASE文件夹里面就是当前项目部署的tomcat配置
Using CATALINA_BASE: "C:\Users\LZJ\.IntelliJIdea2018.3\system\tomcat"
@WebServlet("/abc")//servlet 注解开发可以省略了web.xml里面的设置访问路径
public class SerlerDemo1 implements Servlet { //impServlet接口从写方法
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//程序初始化时执行会执行一次
//因为servlet是单例模式,多用户访问会存在线程安全问题 解决方法:定义局部变量不要定义成员变量
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//每次访问servlet的时候,服务器方法都会被调用
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
//在servlet销毁之前执行一次,一般用于释放资源
}
}
<servlet>
<servlet-name>demo1servlet-name>
<servlet-class>com.lzj.servlet.SerlerDemo1servlet-class>
servlet>
<servlet-mapping>
<servlet-name>demo1servlet-name>
<url-pattern>/demo1url-pattern>
servlet-mapping>
用于获取响应消息数据
GET /day14/demo1?name=zhangsan HTTP/1.1
//GET方法
String getMethod() //获取请求方式GET
String getContexPath() //获取虚拟目录 /day14
String getServeletPath() //获取servlet路径/demo1
String getQueryString() //获取get的请求参数 name=zhangshan
String getRequestURL() //获取url day14/demo1
StringBuffer getRequestURL() //获取完整url :http://locahost/day14/demo1
String getProtocol()//获取http版本
String getRemoteadder()//获取客户机的ip地址
//post请求
BufferedReader getReader() //获取字符输入流,只能操作字符数据
servletInputSteam getInputStream()//获取字节输入流,可以操作所有类型
//通用方法
String getParameter(String name)//根据参数名称获取参数值
String[] getParameterValues(String name)//根据参数名称获取参数值的数组
getParameterNames()//获取所有请求参数名称
getParameterMap()//获取所有参数的map集合
//解决中文乱码问题
req.setCharacterEncoding("utf-8");
//演示获取请求头名称
//1获取请求头名称
Enumeration<String> headerNames = req.getHeaderNames();
//2遍历
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
//根据名称获取请求头值
String value = req.getHeader(name);
System.out.println(name+"---"+value);
}
//通过请求头获取user-agent判断对方用的是什么浏览器
String agent = req.getHeader("user-agent");
//判断agent的浏览器版本
if(agent.contains("Chrome")){
//谷歌浏览器
}else if (agent.contains("Firofox")){
//火狐浏览器
}
//获取请求头数据referer演示放盗连接
String referer = req.getHeader("referer");
if(referer !=null ){
if(referer.contains(("/day14"))){
//正常访问
}else {
//盗连接
}
}
//获取请求消息体--请求参数
//获取字符流
BufferedReader br = req.getReader();
//读取数据
String line = null;
while ((line = br.readLine()) !=null){
System.out.println(line);
}
//转发只能访问当前服务器内部的资源中 转发也是一次请求
//特点:地址栏路径不变 只能访问当地资源 转发是一次请求 可以使用request共享数据
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/目标serlervlet路径");
requestDispatcher.forward(req,resp);
//推荐写法
req.getRequestDispatcher("/目标路径").forward(req,resp);
//request域:代表一次请求的范围,一般用于请求转发多个资源中的共
void SetAttribute(String name,Object obj) //存入数据
Object getAttribute(String name) //通过键获取值
removeAttribute(String name) //通过键不对应的值移除
用来设置消息
//特点:地址栏发生改变 重定向可以访问其他站点 重定向是两次请求 不能使用request共享数据
//访问/当前路径,会跳转到/目标路径
//设置状态码
resp.setStatus(302);
//设置响应头
resp.setHeader("服务器ip","对应的url");
//动态获取虚拟目录
String contextPath = req.getContextPath();
//简单的重定向方法
resp.sendRedirect(contextPath+"url");
//获取对象流之前,设置流的编码
resp.setCharacterEncoding("utf-8");
//告诉浏览器,服务器发送的消息是已utf-8发送的建议他采用utf-8接收
resp.setHeader("content-type","text/html");
//简单方法设置编码格式
resp.setContentType("text/html;charset=utf-8");
//获取字符输出流
PrintWriter pw = resp.getWriter();
//输出数据
//可以输出html标签
pw.write("hello
");
pw.write("afewfwa");
//简单方法设置编码格式
resp.setContentType("text/html;charset=utf-8");
//获取字节输出流
ServletOutputStream outputStream = resp.getOutputStream();
//输出数据
outputStream.write("afda".getBytes("utf-8"));
//ServletContext对象的获取
// 1.通过request对象获取
ServletContext context1 = req.getServletContext();
// 2.通过HttpServlet获取
ServletContext context2 = this.getServletContext();
//ServletContext获取MIME类型
//通过HttpServlet获取
ServletContext context = this.getServletContext();
//定义文件名称
String filename = "a.jpg";
//获取MIME类型
String mimeType = context.getMimeType(filename);
System.out.println(mimeType);
//范围最大的共享所有数据 (使用需很谨慎!!!)
//通过HttpServlet获取
ServletContext context = this.getServletContext();
//获取数据
Object msg = context.setAttribute("msg");
//获取文件真实路径 (把绝对路径变成真实路径)
//通过HttpServlet获取
ServletContext context = this.getServletContext();
//获取文件的服务器路径
String realPath = context.getRealPath("/b.txt"); //获取项目目录下b文件的完整路径
String webinfF = context.getRealPath("/WEB-INF/b.txt"); //获取web-inf下b文件的完整路径
String src = context.getRealPath("/WEB-INF/classes/b.txt"); //获取src下b文件的完整路径
File file = new File(realPath);
作用
//创建Cookie对象
Cookie c1 = new Cookie("msg","hello");
c1.setMaxAge(30); //设置Cookie C1的存活时间>0表示在多少秒后删除 =0直接删除 <0在浏览器关闭后删除
Cookie c2 = new Cookie("name","lzj"); //Cookie可以传递多个
c2.setPath("/"); //c2的Cookie在当前服务器下当前项目下共享 如果2给项目同时setPath("/")同服务器下2个项目可以共享Cookie
//setDomain(String path):如果设置一级域名相同,那么多个服务器之间的Cookie可以共享
//setDomain(".baidu.com")那么tiba.baidu.com和news.baidu.com可以共享
//发送Cookie
resp.addCookie(c1);
resp.addCookie(c2);
//获取Cookie
Cookie[] cs = req.getCookies();
//获取数据,遍历Cookies
if(cs != null){
for (Cookie c : cs) {
String name = c.getName();
String value = c.getValue();
System.out.println(name+":"+value);
}
}
Seecion用于存储一次会话的多次请求数据,可以存储容易类型,任意大小的数据
Seecion于Cookice区别
Seecion原理:Session实现是依赖于Cookie的
HttpSeecion对象:
//使用session共享数据
//获取session
HttpSession session = req.getSession();
//存储数据
session.setAttribute("msg","hello session");
//使用session共享数据
//获取session
HttpSession session = req.getSession();
//获取数据
session.getAttribute("msg");
//期望客户端关闭后,session也能存在
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
resp.addCookie(c);
java服务器端页面 可以直接定义html标签又可以使用<%%>定义java代码
变量名 真实类型 作用
替换和简化jsp页面中的java代码的编写语法:${表达式}
运算:
算数: + - * /(div) %(mod)
比较: > < >= <= == !=
逻辑: &&(and) ||(or) !(not)
空运算:empty 用法
${empty list}:判断字符串、集合等为null且长度为0
${not empty list}:判断字符串、集合等不为null且长度>0
语法:
${域名称.键名}:从指定域中获取指定键的值
域名称
PageScope --> PageContext
requestScope --> request
sessionScope --> session
applicationScope --> applicaton(servletContext)
举例在request存了name=张三 获取:${requestScope.name}
${键名}:依次从最小的域中查找是否有该键对应的值,直到找到为止
获取对象、list、Map
隐式对象:
用于简化和替换jsp页面上的java代码
<%--c:if标签 --%>
<%--test是必须属性接收Boolean表达式 如果为true则显示if标签体内容,如果是false,则不显示标签内容--%>
<%--一般情况下,test属性值会结合el表达式一起使用--%>
<%--c:if标签是没有else c::if标签有else--%>
我是真的
<%
//判断request域中的一个list集合是否为空,如果不为null则显示遍历集合
List list = new ArrayList();
list.add("aaaa");
request.setAttribute("list",list);
%>
遍历集合
<%--完成数字编号对应星期几的案例--%>
<%--1.域中存储一组数字--%>
<%--2.使用choose标签取出数字 相对于switch声明--%>
<%--3.使用when标签做数字判断 相对于case--%>
<%--4.otherwise标签做其它情况的声明 相对于default--%>
<%
request.setAttribute("number",3);
%>
星期一
星期二
星期三
星期四
星期五
星期六
星期天
数字输入有误
<%--foreach:相对于java代码的for语句--%>
<%--1.完成重复操作--%>
<%--for(int i=0;i<10;i++){}--%>
<%--对应属性:begin:开始值--%>
<%--end:结束值--%>
<%--var: 临时值--%>
<%--step:步长 每次运算移动多少步--%>
<%--varStatus:循环状态对象 index:容器中元素索引 count:循环次数--%>
<%--2.遍历容器--%>
<%--List list;--%>
<%--for(User user:list){}--%>
<%--对应属性:items:容器对象--%>
<%--varStatus:循环状态对象 index:容器中元素索引 count:循环次数--%>
${i}
<%
List list1 = new ArrayList();
list1.add("aaa");
list1.add("bbb");
list1.add("ccc");
list1.add("ddd");
list1.add("eee");
request.setAttribute("list1",list1);
%>
${s.index}
${s.count}
${str}
@WebFilter("/*") //直接在类上WebFilter注解 加入访问所有资源之前都会执行该过滤器 如果需要设置访问特定"/访问路径"
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对Request对象请求消息增强
System.out.println("filterDemo1被执行了!");
//放行
filterChain.doFilter(servletRequest,servletResponse);
//回来时是不用重新执行方法的而是直接接着执行放行后面的代码
System.out.println("filterDemo1回来了!");
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>demo1filter-name>
<filter-class>com.lzj.filter.FilterDemo1filter-class>
filter>
<filter-mapping>
<filter-name>demo1filter-name>
<url-pattern>/*url-pattern>
filter-mapping>
//只有浏览器直接请求index.jsp资源时,该过滤器会被执行
//@WebFilter(value = "index.jsp",dispatcherTypes = DispatcherType.ERROR)
//只有浏览器转发访问index.jsp资源时,该过滤器会被执行
//@WebFilter(value = "index.jsp",dispatcherTypes = DispatcherType.FORWARD)
//只有浏览器直接请求index.jsp或者转发index.jsp过滤器就会执行
//@WebFilter(value = "index.jsp",dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})
多用于加载配置文件
public class ContextLoaderListener implements ServletContextListener {
//监听ServletContext对象创建的。ServletContext对象服务器启动后自动创建
//服务器启动后自动调用/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//加载资源文件
//获取servleContext对象
ServletContext servletContext =servletContextEvent.getServletContext();
//加载资源文件
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
//获取真实路径
String realPath = servletContext.getRealPath(contextConfigLocation);
//加载进内存
try {
FileInputStream fis = new FileInputStream(realPath);
System.out.println(fis);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("ServletContext对象被创建了");
}
//在服务器关闭后,ServletContext对象销毁。当服务器正常关闭后该方法被调用
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
<listener>
<listener-class>com.lzj.listenner.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>/applicationContext.xmlparam-value>
context-param>
//获取对象
var div1 = $("#div1");
alert(div1.html());
//通过jq方式获取名叫div的所有html元素对象
var $divs = $("div");
alert($divs); //可以当作对象和数组使用
//对所有的dvi,让内容变成bbb,使用jq方式
$divs.html("bbb")
//监听按钮
$("#b1").click(function () {
//点击事件后
})
//jquery入口函数(dome文档加载完成只后执行该函数中的代码)
$(sunction()){
//监听的代码
})
内容操作
属性操作
通用属性操作
attr():获取/设置元素的属性
removeAttr():删除属性
prop():获取/设置元素的属性
removeProp():删除属性
attr和porp区别?
如果操作的是元素的固有属性(html只带的属性),则建议使用prop
如果操作的是元素的自定义属性,则建议使用attr
对class属性操作
addClass():添加class属性
remoncClass():删除class属性
toggleClass():切换class属性
如果toggleClass(“one”):
判断如果元素对象上存在class=“one”,则将属性值one删除掉。如果原始对象上不存在class=“one”,则添加
CRUD操作
append():父元素将子元素追加到末尾
对象1.append(对象2):将对象2添加到对象1元素内部,并且在末尾
prepend():父元素将子元素追加到开头
对象1.prepend(对象2):将对象2添加到对象1元素内部,并且开头
appendTo()
对象1.appendTo(对象2):将对象1添加到对象2内部,并且在末尾
prependTo()
对象1.prependTo(对象2):将对象1添加到对象2内部,并且开头
after()
对象1.after(对象2):将对象2添加到对应后边,对象1和对象2是兄弟关系
before()
对象1.before(对象2):将对象2添加到对象1前面。对象1和对象2是兄弟关系
insertAfter()
对象1.insertAfter(对象2):将对象2添加到对象1后边。对象1和对象2是兄弟关系
inertBefore()
对象1.isertBefore(对象2):将对象2添加到对象1前面。对象1和对象2是兄弟关系
remove()
对象.remove():将对象删除掉
empty()
对象.empty():将对象的后代元素区别清空,但是保留当前对象其属性点
jq对象.each(callback)
jquery对象.each(function(index,element){})
index:就是元素中的集合的索引
element:就是元素中的每一个元素对象
this:集合中的每一个元素对象
回调函数的返回值
ture:如果当前function返回为false,则结束循环
false:如果当前function返回为true,则结束本次循环,继续下次循环(continue)
$.each(object,[callback])
for…of
for(元素对象 of 容器对象)
jq对象.事件方法(回调函数)
jq对象.事件方法(回调函数)
on绑定事件/off解除事件
jq对象.on(“事件名称”,回调函数)
jq对象.off(“事件名称”,回调函数)
事件切换:toggle
jq对象.toggle(fn1,fn2…)点击第二次就会运行fn2
$.ajax()
语法:$.ajax({键值对})
$.ajax({
url:"",//请求路径
type:"POST",//请求方式
data:{"username":"jack","age":23},//请求数据
success:function (data) {
alert(data)
//请求成功后的回调函数
},
error:function () {
alert("出错啦")
//表示如果请求响应出现错误,会执行的回调函数
},
dataType:"text" //设置接受到的响应数据的格式
})
$.get
语法:$.get(url,[data],[callback],[type])
参数:url:请求路径,data:请求参数,callback:回调函数,type:响应结果的类型
$.get("http://www.baidu.com",{username:"jack",age:23},function (data) {
}),"JSON";
$.post
$.post("http://www.baidu.com",{username:"jack",age:23},function (data) {
}),"JSON";
访问一个servlet,如果是第一次访问就会显示:你好,欢迎您首次访问;如果不是第一次访问会打印欢迎回来上一次访问时间为:YYYY-mm-dd
//设置响应消息体的数据格式以及编码
resp.setContentType("text/html;charset=utf-8");
//获取所有Cookie
Cookie[] cookies = req.getCookies();
boolean flag = false;//没有cookie为lastTime
//判断有数据,获取数据,遍历Cookies
if(cookies != null && cookies.length >0){
for (Cookie cookie : cookies) {
//获取所有Cookies名称
String name = cookie.getName();
if ("lastTime".equals(name)){
//怎么有该cookie不是第一次访问
flag = true; //如果有这个cookie就把flag设置成为true
//设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值
Date date = new Date(); //获取一个当前时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //格式时间
String str_date = sdf.format(date); //解析
str_date = URLEncoder.encode(str_date,"utf-8");//URL编码
cookie.setValue(str_date);//存入cookie
cookie.setMaxAge(60*60*24*30);//设置cookie的存活时间是一个月
resp.addCookie(cookie); //把值写入cookie
//响应数据
//获取cookie的value
String value = cookie.getValue();
value = URLDecoder.decode(value, "utf-8"); //URL解码
resp.getWriter().write("欢迎回来,您上一次的访问时间为:"
+value+"");
break;
}
}
}
if (cookies == null || cookies.length == 0 || flag == false){
//没有对应的cookie 第一次访问
//设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值
Date date = new Date(); //获取一个当前时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //格式时间
String str_date = sdf.format(date); //解析
str_date = URLEncoder.encode(str_date,"utf-8");//URL编码
Cookie cookie = new Cookie("lastTime",str_date); //new一个cookie存入
cookie.setMaxAge(60*60*24*30);//设置cookie的存活时间是一个月
resp.addCookie(cookie);
resp.getWriter().write("你好欢迎首次访问
");
}
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.net.URLDecoder" %><%--
Created by IntelliJ IDEA.
User: LZJ
Date: 2019/5/16
Time: 19:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
//获取所有Cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;//没有cookie为lastTime
//判断有数据,获取数据,遍历Cookies
if(cookies != null && cookies.length >0){
for (Cookie cookie : cookies) {
//获取所有Cookies名称
String name = cookie.getName();
if ("lastTime".equals(name)){
//怎么有该cookie不是第一次访问
flag = true; //如果有这个cookie就把flag设置成为true
//设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值
Date date = new Date(); //获取一个当前时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //格式时间
String str_date = sdf.format(date); //解析
str_date = URLEncoder.encode(str_date,"utf-8");//URL编码
cookie.setValue(str_date);//存入cookie
cookie.setMaxAge(60*60*24*30);//设置cookie的存活时间是一个月
response.addCookie(cookie); //把值写入cookie
//响应数据
//获取cookie的value
String value = cookie.getValue();
value = URLDecoder.decode(value, "utf-8"); //URL解码
%>
欢迎回来,您上一次的访问时间为:<%=value%>>
<%
break;
}
}
}
if (cookies == null || cookies.length == 0 || flag == false){
//没有对应的cookie 第一次访问
//设置Cookie的value 获取当前时间的字符串,重新设置Cookie的值
Date date = new Date(); //获取一个当前时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //格式时间
String str_date = sdf.format(date); //解析
str_date = URLEncoder.encode(str_date,"utf-8");//URL编码
Cookie cookie = new Cookie("lastTime",str_date); //new一个cookie存入
cookie.setMaxAge(60*60*24*30);//设置cookie的存活时间是一个月
response.addCookie(cookie);
%>
您好,欢迎首次登陆
<%
}
%>
int width = 100;
int height = 50;
//创建一个对象,在内存中的图片(验证码图片)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//美化图片
Graphics g = image.getGraphics(); //画笔对象
g.setColor(Color.PINK); //设置画笔颜色
g.fillRect(0,0,width,height); //填充宽高
//画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width -1 ,height - 1);
String str ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
//创建随机角标
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i =1;i<=4;i++){
int index = random.nextInt(str.length());
//获取字符
char ch = str.charAt(index); //随机字符
sb.append(ch);
//写验证码
g.drawString(ch+"",width/5*i,height/2);
}
String checkCode_session = sb.toString();
//将验证码存入session
req.getSession().setAttribute("checkCode_session",checkCode_session);
//画干扰线
g.setColor(Color.GREEN);
//随机生成画线坐标点
for(int i =0;i<10;i++){
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
g.drawLine(x1,x2,y1,y2);
}
//将图片输出页面
ImageIO.write(image,"jpg",resp.getOutputStream());
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script>
//点击超链接或者图片需要换一张
// 1.一定是给超链接和图片绑定点击事件
// 2.修改或者重新设置图片的src值
window.onload=function() {
//1获取图片对象
var img = document.getElementById("checkCode");
var a = document.getElementById("change");
//2绑定点击事件
img.onclick = function(){
//加时间戳
var date = new Date().getTime();
img.src="/day13/checkCodeServlet?"+date;
}
a.onclick = function(){
//加时间戳
var date = new Date().getTime();
a.src="/day13/checkCodeServlet?"+date;
}
}
script>
head>
<body>
<img id="checkCode" src="/day13/checkCodeServlet"/>
<a id="change" href="">看不清,换一张a>
body>
html>
//解决文件下载中文乱码工具类
public static String getFileName(String agent,String filename)throws UnsupportedEncodingException {
if (agent.contains("MSIE")){
//IE浏览器
filename = URLEncoder.encode(filename,"utf-8");
filename = filename.replace("+"," ");
}else if (agent.contains("Firefox")){
//火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
}else{
//其他浏览器
filename = URLEncoder.encode(filename,"utf-8");
}
return filename;
}
//获取请求参数
String filename = req.getParameter("filename");
//使用字节输入流加载文件进内存
//找到文件服务器路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//用字节流关联
FileInputStream fis = new FileInputStream(realPath);
//设置resp响应头
//设置响应头类型content-type
String mimeType = servletContext.getMimeType(filename); //获取文件的Mime类型
resp.setHeader("content-type",mimeType);
//设置响应头打开方式:content-disposition
//解决中文文件名问题
//获取user-ageni请求头
String agent = req.getHeader("user-agent");
//使用工具类方法编码文件名
filename = DownLoadUitls.getFileName(agent, filename);
resp.setHeader("content-disposition","attachment;filename="+filename);
//将输入流的数据写出到输出流中
ServletOutputStream sos = resp.getOutputStream();
byte[] buff = new byte[1024*8];
int len =0 ;
while ((len = fis.read(buff)) != -1){
sos.write(buff,0,len);
}
fis.close();
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<a href="/day13/downLoadServlet?filename=a.jpg">图片1a>
body>
html>