图像
图片放到 webroot 下的一个文件夹 image 里面
可以在浏览器直接输入 http://localhost:8080/servlet/image/1.jpg 即可显示图片
l 可以用标签 <img src=”” width=” " height=” “ />
l 建一个能生成图片的 servlet ,让它继承一个叫 HttpServlet 类,为什么该继承呢? HttpServlet 已经实现了 Servlet 接口,因为这个类用起来方便,
l 适配器模式:有一个接口,里面有许多方法;要求某一个类必须实现这个接口,大多情况下这个类会写一部分方法,其他方法什么也不干,保留在类中;再建另一个类继承上一个类,这个类随便实现父类的方法与否。
l servlet 类中有 doGet doPost 方法;或者通过 service 方法,它会根据判断请求方式,可以处理两种请求, HttpServletReques 是 ServletRequest 接口的子接口,这样看来 ServletRequest 用处不大,这叫过度设计,会导致系统很复杂,
画图步骤
1, 在内存中生成位图(图片最原始格式的是 bmp 格式),如 windows 的画图程序,位图在计算机以二进制数据保存,有一个一个亮点组成 1024×768 ,表示横店 1024 个点,竖 768 ; 28 位 表示一个点 3 个字节,每个是 8 位,每个字节表示一种颜色,红绿蓝(都为 0 ~ 255 ),一般在网上传都不用 bmp 格式因为它太大了,所以都用压缩格式: jpeg 格式。
2, 压缩成 JPEG
3, 输出
l BufferdImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB); 像素是 200×200 第三 , 个参数用理会,
Graphics g = image.getGraphics();// 封装了一些画笔操作
Random r = new Random();
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)); 红色 //0~255
// g.drawString("Hello", 50, 50); 可以这样写文字
g.fillRect(0,0,200,200); 矩形 ,1 , 2 参数是左上表达坐标, 3 , 4 是长和宽
// 其实 response.getWriter ()和
response.setContentType(“image/jpeg”);// 告诉浏览器你送的不是文本而是图片格式
OutputStream os = response. getOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os); (new FileOut…// 可放到文件中它是一边压缩一边把压缩的内容输出, BufferedImage 需要有一个输出流跟它管理。
l 在页面做个链接
l <a href=”javascript:alert(‘hello’)”> 看不清 </a>
l <a href=”” οnclick=”alert(“hello”)> 看不清 </a>// 这样执行 onclick 后还会执行廉洁,这样颜色发生改变
l <a href=”javascript:;” οnclick=”alert(“hello”)>// 一般都喜欢这么写, 点这个之后就只是运行 onclick ,而不会进行连接,这样图片颜色也不改变,
<a href=”javascript: alert(‘hello’);” >// 也可这样写,但是有点小毛病,看 状态栏显示,显示 javascript: alert(‘hello’); 这样不是很好,程序员不希望被别人看到自己的隐私,其实也没什么,一般人都不看,
不可以直接这么写 <a href=” alert(‘hello’);” >
l <a href=”javascript:;”οnclick=”document.getElem…(‘image1’).src=’../img1.jpg’” >// 浏览器只要发现 src 的值被改了就会重新访问 src 地址,浏览器只是刷新图片,而不是整个页面都刷新,修改的 src 跟以前必须不一样,所以 (‘image1’).src=’../image’ 是不行的,但是可以添加一个 get 请求方式,给一个参数就可以了, (‘image1’).src=’../image?12345’ 它仍然是访问那个 servlet 。 tomcat 只把 ? 前边的当作地址, 可以让参数每次不一样,可以用 (‘image1’).src=’../image?’+(new Date()).getTime()” ,将 onclick 写到图片上就可以了。
l 添加 function changeImage(){
var imag = document.getElement..(“image1”);
imag.src = “image?new Date()”;
上传图片
在实际开始的时候不一定等需求都做好了才编码。
在传图片的时候不能用 Post 协议传, name=”…”&… 很难表示;
使用 commons-uploadfile.jar
l 先建一个叫 UploadFileServlet 生成页面 , 它接受的是 get 请求,因为没有东西要提交给它。
根目录叫 : uploadfile, 路径: uploadfile
在 servise 里:
PrintRiter out = response.getWriter();
out……
out.println(“<form name=”desc” action=’uploadfile’ method=’post’enctype=’multipart/form-data’>”) ;// 编码的种类 , 一定要有,不写的话就用默认的设置,默认只能传文本(如 ?name=’lili’&age=’20’ ),如果传二进制文件就必须这样写。
out.println(“<td> <input type=‘file’ name=‘file’/>);
l 再写一个 UploadActionServlet 用于开始上传,生成 doPost() 方法。
doPost(){
/*InputStream is = request.getInputStream();;// 获得浏览器上传的数据
Sys…(is.read());// 读一个字节看是什么,输出的是 45 ,这个输出并不是文件的开头那个字节,
Sys…(is.available);// 可以读到的流的字节数,为 0 ,这个方法是个不可靠的方法,用这个流比较费事 */
n 用下面:
DiskFileItemFactory dfif = new DiskF….();// 这个对象该对象可以用于控制性能方面的参数,比如指定缓存,上到 struts 再详细说,
ServletFileUpload upload = new ServletFileUpload(dfif);// 这个重要,它封装了上传数据的解析过程(获取方法),真正用于获取文件信息的是 upload
upload.setSizeMax(1024*1024);// 上传文件大小,这个必须要设置 ,否则黑客很容易捣乱,它只要传个超大的文件,那么你的系统就垮了
List<?> list = upload.parseRequest(request);// 让 upload 去解析
/*Sys…(list);// 打印出来看看,
for(int I = 0;i<list.size();i++){
FileItem item = (FileItem)list.get(i);
//list 里面放的是 FileItem 对象,一个 list 表示一个文件,如果要传好几个文件,那么一个 FileItem 用来封装一个上传文件的信息。可以通过 FileItem 来获取文件的信息,通过输入流获取文件的内容,只要借一个输出文件流从输入流拷贝内容出来
// 打印出了 commons.fileupload.disk.DiskFileItem
*/
FileItem fileItem = (FileItem)list.get(0);
Sys…(fileItem.getName());//happy.JPG 就是文件名称 , 如果是非文件的话 ( 普通文本框 ), 返回 null
Sys…(FileItem.isFormFiled());// 如果是 false 表示为文件,是 true 则是通常的一个表单
request.getParameter(“desc”);// 不能用来获取文件,只能获取参数,返回值是空的。
Sys…(FileItem.getFileName()); // 获得对应表单的 name 值
Sys…(FileItem.getString());// 可以是文本框的值,
Sys…(fileItem.getSize());// 文件的大小
Sys…(FileItem.getInputStream());// 你上传的那个文件用到文件流
FileOutputStream os = new F…(fileItem.getName);
InoutStream is = fileItem.getInputStream();
IOUtils.copy(is,os);// 从输入流拷贝到输出流,这样不用写 for 循环
is.close();
os.close();
默认传到 tomcat/bin 下面,可是图片坏了,显示不出来,那是因为流没有关闭。
运行:
报错: NoClassDefFoundError/…, 你这个系统用到某个开源组件,这个组件你虽然导进去了,但是这个组件又需要其他的开源包,你少了这个,就报这个错,如少了 common-io.1.4.jar 包没有导入。导入就 OK 。
l ServletFileUpload fileUpload = …
List<FileItem> list = fileUpload.parseRequest(request);
FileItem item = (FileItem);ist.get(0);
item.getName();
item.getSize();
item.getInputStream();
l 做一个文件上传,然后把文件内容打印到控制台
DiskFileItemFactory dfif = new DiskF….();
ServletFileUpload upload = new ServletFileUpload(dfif); upload.setSizeMax(1024*1024);
List<?> list = upload.parseRequest(request);// list 放到都是 fileItem, 用 List 不够好,用 Map 比较好。
如果做排序或做插入用 List 集合,如果找其中的身份证号是谁,就用 map ,往往 key 是 value 的一部分, map.put(person.getName(),person); 找到时候: Person p =(Person)map.get(“java”); 针对什么查找就什么做键,另外的做值,
Map<String,FileItem> map = HashMap<String,FileItem>;
for(int I = 0;i<list.size();i++){
FileItem item = (FileItem)list.get(i);
map.put(item.getFieldName(),item);
}
这样就很方便:
FileItem file = map.get(“file”);
map.get(“desc”);
map.get(“file”);// 这是个通常的编程技巧,这样可以方便的交互访问
Sys…(map.get(“desc”).getString());
FileItem file = map.get(“file”);// 返回的是 fileItm
我想存到服务器端,我不想用他原来的名字,它的名字可能乱七八糟,我们用当前系统的毫秒数做文件名 , 一般服务器不会使用你提交的文件名
String name = file.getName();
file.getName().subString(name.lastIndexOf(“.”));// 包括了小点
String fileName=String.valueOf(“System.currentTimeMillis()+name);
File up = new File(fileName);
file.write(up);// 这个比上面还简单 , 文件不需要关,文件流才要关 , 用流也行,记得要关了。
l 一般不传到默认路径( tomcat/bin 下)
改为:
String dir=”upload”;
ServletContext ctx = getServletContext();// 这玩意有时候也会用
File up = new File(“upload”,fileName);
l 经典案例:点浏览——选文件——文件描述——提交。再写一个 Servlet 展示图片。
写两个 Servlet 一个负责上传,一个负责展示出来
数据库有一张表,存文件名
数据表里面不存图片,因为将来拿出来的时候效率很低,图片不涉及到查找问题,所以放名字进去就可以,现在还不能说把一个人的图片放进去找个一模一样的照片出来,不过以后可能会这样搜索 。
n 上传要做两件事:上传,写入数据库
n 显示图片也要做两件事:读数据库信息,生成一个 HTML 通过 for 循环输出 <img src…./> 显示图片, upload/…
n 通过重定向,点击确定上传的时候就直接显示图片,数据库的访问都用 DAO 封装
Servlet 生命周期
1, 客户端发送请求—— > 容器
2, 容器解析请求
3, 容器创建 Servlet 实例
4, 容器调用 init ()方法
5, 容器调用 service ()方法
6, 容器输出相应
7, 容器返回响应—— > 客户端
8, 容器调用 destroy 方法