1.编码和解码
当内存中的数字被解释为字符(文字和符号)时,就是解码过程,把文字和符号用数字定义时就是编码。
//服务器默认编码为ISO8859-1,它不支持中文,tomcat规定的
//resp.setCharacterEncoding("UTF-8");//指定对服务器响应进行重新编码的编码
//指定对服务器响应进行响应头的设置,告诉浏览器响应头的字符集格式是UTF-8。
//resp.setHeader("Content-Type","text/html;charset=utf-8");
//指定对服务器响应进行重新编码的编码,和告诉浏览器响应字符集格式是UTF-8。
resp.setContentType("text/html;charset=UTF-8");
ServletOutputStream outputStream = resp.getOutputStream();
outputStream.write("哈哈".getBytes("utf-8"));//默认采用本地编码gbk
PrintWriter writer = resp.getWriter();
writer.write("你好");
2.文件下载
文件名的编码问题,和设置响应头为下载
//通过路径得到一个输入流
String path = this.getServletContext().getRealPath("/WEB-INF/classes/05.jpg");
FileInputStream fis=new FileInputStream(path);
//创建输出流,输出浏览器
ServletOutputStream outputStream = resp.getOutputStream();
//得到要下载的文件名
String substring = path.substring(path.lastIndexOf("\\") + 1);
System.out.println(substring);
//设置文件名编码
URLEncoder.encode(substring,"UTF-8");
resp.setHeader("content-disposition","attachment;filename="+substring);
//执行输出
int len=0;
byte[] b=new byte[1024];
while((len=(fis.read(b)))!=-1){
outputStream.write(b,0,len);
}
3.验证码
设置验证码图片
@WebServlet(urlPatterns = "/demo3")
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width=110;
int height=25;
//在内存中创建一个图像对象
BufferedImage img=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//创建一个画笔
Graphics g=img.getGraphics();
//给图片添加背景色
g.setColor(Color.GREEN);
//xy为坐标,windth和height为高宽
g.fillRect(1,1,width-2,height-2);
//设置文本样式
g.setColor(Color.BLACK);
g.setFont(new Font("宋体",Font.BOLD,17));
//给图片添加文本
Random rand=new Random();
int position=20;
for (int i=0;i<4;i++){
g.drawString(rand.nextInt(10)+"",position,20);
position+=20;
}
//加上干扰线
for (int i=0;i<9;i++){
g.drawLine(rand.nextInt(width),rand.nextInt(height),rand.nextInt(width),rand.nextInt(height));
}
//将图片对象以流的方式输出客户端
ImageIO.write(img,"jpg",resp.getOutputStream());
}
}
jsp页面<script type="text/javascript">
function changeCode(){
var img=document.getElementsByTagName('img')[0];
//解决缓存问题
img.src="${pageContext.request.contextPath}/demo3?time="+new Date().getTime();
}
</script>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form>
验证码:<input type="text"><img src="${pageContext.request.contextPath}/demo3">
<a href="javascript:changeCode()">看不清换一张</a>
</form>
</body>
</html>
可以使用工具类实现验证码,需要引入ValidateCode.jar
刷新并且跳转网页
resp.setIntHeader("refresh",1);//1秒刷新页面
resp.setHeader("refresh","3;url="xxxxx");//设置3秒跳转xxxxx页面
转发和重定向
转发:浏览器地址不变,可以带request和response
重定向:浏览器地址会变,并且不能带request和response
基础(理解302是重定向,location是转换地址)
@WebServlet(urlPatterns = "/demo4")
public class ServletDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);//响应码302,告诉浏览器是重定向
//重定向的位置
resp.setHeader("location","http://write.blog.youkuaiyun.com/");
}
}
进阶(此方法是对上面的代码进行封装,所以无非封装的都是响应头,响应行,响应消息体,而已,以后在别的语言没有sendRedirect方法,我们也知道怎么创造轮子)
resp.sendRedirect("url");
判断不同浏览器
@WebServlet(urlPatterns = "/demo5")
public class ServletDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String header = req.getHeader("User-Agent");
System.out.println(header);
if(header.toLowerCase().contains("msie")){
System.out.println("你使用的是IE浏览器");
}else if(header.toLowerCase().contains("firefox")){
System.out.println("你使用的是火狐浏览器");
}else if(header.toLowerCase().contains("chrome")){
System.out.println("你使用谷歌浏览器");
}
}
}
解决请求参数乱码问题
post 乱码问题
req.setCharacterEncoding("utf-8"); //设置请求编码格式 注:浏览器使用什么编码传过来就是什么编码
get乱码问题
String name=new String(name.getBytes("ISO-8859-1"),"UTF-8");
内省(Introspector) JavaBean
基础:开发框架时,经常需要使用java对象的属性来封装数据,每次用反射技术过于麻烦,所以sun公司提供了一套api,专门操作java对象的属性。
public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
//创建Student对象
Student s=new Student();
//获取Student类中的name属性
PropertyDescriptor pd=new PropertyDescriptor("name",Student.class);
Method writeMethod = pd.getWriteMethod();
Method readMethod = pd.getReadMethod();
//设置s对象中name属性为小明
writeMethod.invoke(s,"小明");
//获取s对象中name的属性值
System.out.println(readMethod.invoke(s, null));
}
高级:使用内省对request的请求参数进行封装(前提,实体类和请求参数name一致!)
Map<String, String[]> map = req.getParameterMap();
Student s=new Student();
for (Map.Entry<String,String[]> m:map.entrySet()) {
String key = m.getKey();
String[] value = m.getValue();
try {
//获取当前Student中表单对应的key对应的Student的属性
PropertyDescriptor descriptor = new PropertyDescriptor(key, Student.class);
//创建属性描述器
if(value.length==1){
writeMethod.invoke(s,value[0]);//给一个值的变量赋值
}else{
writeMethod.invoke(s,(Object) value);//多个值的变量赋值(如复选框)
}
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
终极:使用commons-beanutils.jar对属性进行封装,使用前提还需要commons-logging.jar日志架包
Map<String, String[]> map = req.getParameterMap();
Student s=new Student();
for (Map.Entry<String,String[]> m:map.entrySet()) {
String key = m.getKey();
String[] value = m.getValue();
try {
//使用beanUtiles框架的好处就是一步到位,简单
BeanUtils.populate(s,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
请求包含
forward()方法
-
- forward()方法的处理流程如下:(1)清空用于存放响应正文数据的缓冲区;(2)如果目标组件为Servlet或JSP,就调用它们的service()方法,把该方法产生的响应结果发送到客户端,如果目标组件为文件系统中的静态html文档,就读去文档中的数据并把它发送到客户端。
- 由于forward()方法先清空用于存放响应正文数据的缓冲区,因此servlet源组件生成的响应结果不会被发送到客户端,只有目标组件生成的结果才会被发送到客户端;
- 如果源组件在进行请求转发之前,已经提交了响应结果(例如调用了flushBuffer方法,或者close()方法),那么forward()方法会抛出IllegalStateException。为了避免该异常,不应该在源组件中提交响应结果。
- include()方法
- 源主键与被包含的组件输出的数据都将添加响应结果中
- 在目标组件中对响应状态代码或者响应头所做的修改都会被忽略