severlet上传单个文件
使用注解@MultipartConfig将⼀个 Servlet 标识为支持文件上传
Servlet 将 multipart/form-data 的 POST请求封装成Part对象, 通过Part对上传的文件进行操作
常用方法
public Collection <String> getHeaderNames()
// 用于从该部分数据所包含的请求头中获取所有
public String getHeader(String name)
//用于从该部分数据所包含的请求头中获取指定字段名称对应的单个取值
public Collection<String> getHeaders(String name)
//用于从该部分数据所包含的请求头中获取指定字段名称对应的所有取值
public String getName()
//用于获取该部分数据对应的表单组件的名称
public String getSubmittedFileName()
//用于获取用户所上传文件的原始名称
public long getSize()
//用于获取该部分数据中正文数据的大小,对于文件上传操作来说,就是获取所上传文件的大小
public String getContentType()
//用于获取该部分数据中正文数据的 MIME 类型,与请求头中content-type 字段对应
public void write(String fileName) throws IOException
//用于将该部分数据中的正文数据写⼊到指定文件中,对于文件上传操作来说,就是将文件内容写⼊到指定文件中
public void delete() throws IOException
//用于删除该部分数据对应的缓存文件
public InputStream getInputStream() throws IOException
//该方法用于返回一个字节输⼊流,通过该流可以读取该部分数据中的正文数据
字段的名称组成的集合
文件上传需要将form表单的enctype属性设置为multipart/form-data, 此时发送网络请求时的请求头中的content-type就是multipart/form-data,该内容类型会将请求提交的数据,以多段的形式进行拼接(每一个表单项就是一段),然后以二进制流的形式发送给服务器。
上传单个文件
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<input type="submit" value="上传多个文件">
</form>
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//上传一个文件
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
Part file = req.getPart("file");
String submittedFileName = file.getSubmittedFileName();
//获取上传的文件名
String name = submittedFileName;
String dir = "E:\\load";
submittedFileName = dir + File.separator + submittedFileName;
File file1 = new File(submittedFileName);
if (!file1.getParentFile().exists()){
file1.getParentFile().mkdirs();
}
try{
file.write(submittedFileName); //写到默认路径中
String s = "<a href='/download?file=" + submittedFileName + "' >下载图片</a>";
resp.getWriter().write(s); //输出到页面上
System.out.println("上传文件成功");
}catch (IOException e){
e.printStackTrace();
System.out.println("上传文件失败");
}
}
上传多个文件
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//上传多个文件
String remoteAddr = req.getRemoteAddr();
if ("0:0:0:0:0:0:0:1".equals(remoteAddr)){
remoteAddr = "127.0.0.1";
}
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
Collection<Part> parts = req.getParts();
String link = "";
String message = "";
for (Part part:parts) {
String contentType = part.getContentType();
//获取图片的格式
String fileName = part.getSubmittedFileName();
//获取文件名
if (Constant.ALLOW_TYPES.contains(contentType)){
File file = new File(Constant.UPLOAD_PATH + File.separator + fileName);
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
part.write(fileName);
String s = "<a href=http://10.0.3.149/download?file=" + fileName + ">下载"
+ fileName.substring(0,fileName.lastIndexOf(".")) + "</a>";
link += s + "</br>";
message += "<p>" + fileName + "上传成功</p>";
FilesDao filesDao = new FilesDao();
try {
boolean insert = filesDao.insert(remoteAddr,fileName.substring(0,fileName.lastIndexOf(".")),contentType,file.length(),Constant.getTime(file.lastModified()),s);
if (insert){
System.out.println("上传数据库成功:" + fileName);
}else {
System.out.println("上传数据库失败:" + fileName);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}else{
message += "<p>" + fileName + "上传失败,文件格式不支持</p>";
}
}
String html = "<html><body>";
html += message;
html += "<p>下载地址如下:</p>";
html += link;
html += "</body></html>";
resp.getWriter().write(html);
}else {
System.out.println("请重新登陆");
resp.sendRedirect(req.getContextPath() + "/error.html");
}
}
下载单个文件
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//下载一个文件
resp.setContentType("application/octet-stream");
//二进制流下载
String file = req.getParameter("file");
//获取上传的时候定义的name属性的值 file
resp.setHeader("Content-disposition","attachment;filename=" + file);
String path = Constant.UPLOAD_PATH + File.separator + file;
ServletOutputStream outputStream = resp.getOutputStream(); //获取相应输出流(二进制)
FileInputStream fileInputStream = new FileInputStream(path);
fileInputStream.transferTo(outputStream);
fileInputStream.close();
outputStream.close();
}
会话
用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应
会话跟踪
一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据HTTP
协议是无状态的,每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内数据共享
实现
-
客户端会话跟踪技术:Cookie
-
服务端会话跟踪技术:Session
Cookie
发送Cookie
1、创建Cookie对象,设置数据
Cookie cookie = new Cookie("key","value");
2、发送Cookie到客户端:使用response对象
response.addCookie(cookie);
获取Cookie
3、获取客户端携带的所有Cookie,使用request对象
Cookie[] cookies = request.getCookies();
4、获取客户端携带的所有Cookie,使用request对象
for循环
5、使用Cookie对象方法获取数据
cookie.getName();
cookie.getValue();
6、设置Cookie存活时间
默认情况下,Cookie 存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁
cookie.setMaxAge(int seconds)//设置存活时间,存储在浏览器所在的硬盘
正数:将 Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除 负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则 Cookie被销毁 零:删除对应 Cookie
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//发送Cookie
//创建Cookie对象
Cookie cookie=new Cookie("username","zs");
//设置存活时间:一分钟
cookie.setMaxAge(60);
//发送Cookie.response
response.addCookie(cookie);
}
存储中文
Cookie 不能直接存储中文,如需要存储,则需要进行转码:URL编码
//发送Cookie
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//发送Cookie
//创建Cookie对象
String value="张三";
//URL编码
value= URLEncoder.encode(value,"UTF-8");
Cookie cookie=new Cookie("username",value);
//设置存活时间:一分钟
cookie.setMaxAge(60);
//发送Cookie.response
response.addCookie(cookie);
}
//获取Cookie
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Cookie
//获取Cookie数组
Cookie[] cookies = request.getCookies();
//遍历数组
for (Cookie cookie : cookies) {
//获取数据
String name = cookie.getName();
if("username".equals(name)){
String value = cookie.getValue();
//URL解码
value = URLDecoder.decode(value , "UTF-8");
System.out.println(name+":"+value);
}
}
}
Session
1、获取Session对象
HttpSession session = request.getSession();
2、Session对象功能
void setAttribute(String name, Object o)//存储数据到 session 域中
Object getAttribute(String name) //根据 key,获取值
void removeAttribute(String name) //根据 key,删除该键值对
//请求1
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//存储到Session中
//获取Session对象
HttpSession session=request.getSession();
//存储数据
session.setAttribute("username","zs");
}
//请求2
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取数据,从Session中
//获取Session对象
HttpSession session=request.getSession();
//获取数据
Object username = session.getAttribute("username");
System.out.println(username);
}
Session 钝化、活化
-
钝化:在服务器正常关闭后, Tomcat会自动将 Session数据写入硬盘的文件中
-
活化:再次启动服务器后,从文件中加载数据到Session中
底层原理:Session是基于Cookie来实现的
Seesion 销毁
默认情况下,无操作,30分钟自动销毁(在web.xml中)
<web-app> <session-config> <session-timeout>30</session-timeout> </session-config> </web-app>
调用 Session对象的 invalidate()方法(销毁自己)
//销毁 session.invalidate();
Cookie 和 Session 区别
存储位置:Cookie 是将数据存储在客户端,Session 将数据存储在服务端 安全性:Cookie 不安全,Session 安全 数据大小:Cookie 最大3KB,Session 无大小限制 存储时间:Cookie 可以长期存储,Session 默认30分钟 服务器性能:Cookie 不占服务器资源,Session 占用服务器资源
三层架构
三层架构(3-tier architecture) 就是将整个业务应用划分为:
-
界面层(User Interface layer) UI
-
业务逻辑层(Business Logic Layer) BLL
-
数据访问层(Data Access layer) DAL
表示层 表示层,又称界面层,是与用户交互的界面。位于最外层/最上层,离用户最近,用于接收用户输入的数据和显示处理后用户需要的数据。
【接受请求,封装数据,调用业务逻辑层,响应数据(servlet,jsp)】
业务逻辑层 业务逻辑层,又称服务层,是表示层和数据访问层之间的桥梁。位于中间层,用来处理业务逻辑,具体包含:验证、计算、业务规则等等。 数据访问层 数据访问层,是对数据库访问的层。位于最里层/最下层,主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。 层与层的关系:表示层依赖于业务逻辑层,业务逻辑层依赖于数据访问层
Entity(实体层):它不属于三层中的任何一层,但是它是必不可少的一层 Entity在三层架构中的作用: 1、实现面向对象思想中的"封装"; 2、贯穿于三层,在三层之间传递数据;(注:确切的说实体层贯穿于三层之间,来连接三层) 3、每一层(UI—>BLL—>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。
三层架构的出现就是为了“高内聚,低耦合”
内聚:一个模块内各个元素的关联度。 耦合 :各个模块之间的关联度。 高内聚 :尽可能一个类/模块只负责一个功能(一个模块内的元素关联度,越容易理解、修改和维护,出错就越少)。 低耦合 :模块与模块之间的关联度要尽可能的低,避免牵一发而动全身 从类角度来看:高内聚低耦合:减少类内部,对其他类的调用 从功能块来看:高内聚低耦合:减少模块之间的交互复杂度