WEB后端_Day04(文件上传、文件下载、EL表达式、JSTL标签库、页面JSP动态化、后端代码优化)

WEB后端_Day04(文件上传、文件下载、EL表达式、JSTL标签库、页面JSP动态化、后端代码优化)

文件上传

前端:

  1. 表单的提交方式必须是post
  2. enctype=“multipart/form-data”
  3. 文件上传的input的type = file

后端:commonsFileupload commonsIO
步骤:

  1. 判断当前提交的表单是否是 multipart/form-data
  2. 获取ServletFileUpload
  3. 使用ServletFileUpload对象来解析请求
  4. 遍历解析而来的元素列表
  5. 判断每一个元素是普通表单元素还是文件上传
  6. 如果是普通表单 直接获取值即可 String str = item.getString();//表单元素的value属性值
  7. 如果是文件上传

获取文件名称
设置文件保存的目录
给文件设置一个新的名称 UUID.randomUUID().toString() +文件的本身的扩展名
使用fileItem.write(文件保存的目录) fileItem是文件上传项

文件下载

页面前端:
​ 待下载文件的列表(使用超链接a标签)
思路:当我们点击超链接的时候 提交一个请求到服务端的一个servlet处理我们下载的请求,在请求中 我们需要告诉服务器 需要下载的文件的名称(或者id)。

idpathuuidnamerealNameexpcreatetime
120210402f68d9aaa-1f45-43b2-928b-622817b7972aab.jpg2021-04-03 15:23

后端:

  1. 获取前端传递过来的要下载的文件的id
  2. 通过id查询要下载的文件的详细信息
  3. 组合文件在服务器上的对象
  4. 设置文件下载的属性response.setHeader(“Content-Disposition”, “attachment; fileName=1.jpg”);
  5. 创建一个文件的输入流
  6. 使用流将文件保存到一个位置
<a href="download?path=20210402/8aadd81a-81d6-42e4-96d6-51e0dcb68cb4.doc">待下载文件</a>

servlet

package cn.lanqiao.controller;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*

public class DownloadServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取要下载文件的路径
         String path = req.getParameter("path");
         //设置响应头  作为附件附件
         resp.setHeader("Content-Disposition", "attachment; fileName=课堂笔记.doc");
         //获取文件的minetype
        ServletContext context = getServletContext();
        String minetype = context.getMimeType("e://upload/"+path);
        //设置响应的内容类型
        resp.setContentType(minetype);
        //获取响应的输出流
        OutputStream os =  resp.getOutputStream();
        //获取要下载的文件的输入流
        InputStream is = new FileInputStream(new File("e://upload/"+path));
        //实现文件的下载
        IOUtils.copy(is,os);
    }
}

解决下载过程中文件的名称为中文时的中文乱码问题

  //解决中文乱码  对Content-Disposition内容进行编码 浏览器会自动解析URLEncoder编码的字符串
        String  contentValue = "attachment; fileName="+URLEncoder.encode("课堂笔记.doc","UTF-8");
         resp.setHeader("Content-Disposition", contentValue);

EL 表达式

jsp脚本的问题:

  1. 格式嵌套 不适合于复杂的嵌套

  2. html代码和java代码混合在一起 使得程序不易于维护

什么是EL 表达式,EL 表达式的作用

EL 表达式的全称是:Expression Language。是表达式语言。

EL 表达式的什么作用:EL 表达式主要是代替jsp 页面中的表达式脚本在jsp 页面中进行数据的输出。因为EL 表达式在输出数据的时候,要比jsp 的表达式脚本要简洁很多

  <h1>jsp脚本取值</h1>
    <%=request.getAttribute("req")%><br/><br/>
    <%=request.getAttribute("req1")%><br/><br/>
    <%=request.getAttribute("req2")%><br/><br/>
  <h1>EL表达式</h1>
    ${requestScope.req}<br/><br/>
    ${req1}<br/><br/>
    ${requestScope.req2}

EL 表达式的格式是:${表达式}

EL 表达式在输出null 值的时候,输出的是空串。jsp 表达式脚本输出null 值的时候,输出的是null 字符串

EL 表达式搜索域数据的顺序

EL 表达式主要是在jsp 页面中输出数据。主要是输出域对象中的数据。

当四个域中都有相同的key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去进行搜索,找到就输出。

req.setAttribute("key","value1");
req.getSession().setAttribute("key","value2");
req.getServletContext().setAttribute("key","value3");
 ${key}

表达式输出Bean 的普通属性,数组属性。List 集合属性,map 集合属性

  1. 需求——输出Person 类中普通属性,数组属性。list 集合属性和map 集合属性。
public class Person {
    private String name;
    private String[] phones;
    private List<String> citys;
    private Map<String, Object> hoby;
 @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Person person = new Person();
        person.setName("张三");
        person.setPhones(new String[]{"188888888","19999999","1555555555"});
        List<String> citys = new ArrayList<>();
        citys.add("太原");
        citys.add("运城");
        citys.add("临汾");
        person.setCitys(citys);
        Map<String, Object> hobys = new HashMap<>();
        hobys.put("basketball","篮球");
        hobys.put("footb","足球");
        person.setHoby(hobys);
        req.setAttribute("person",person);
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }
  <body>
    <h1>获取对象的属性</h1>
    姓名:${person.name}<br/><br/>
    电话:${person.phones[0]}<br/><br/>
    城市:${person.citys[1]}<br/><br/>
    爱好:${person.hoby.basketball}
  </body>

获取数组和集合及map的所有元素

 <h1>获取对象的属性</h1>
    姓名:${person.name}<br/><br/>
    电话:${person.phones}<br/><br/>
    城市:${person.citys}<br/><br/>
    爱好:${person.hoby}

表达式——运算

语法:${ 运算表达式} , EL 表达式支持如下运算符:

  1. 关系运算
关系运算符说 明范 例结果
== 或 eq等于${ 5 == 5 } 或 ${ 5 eq 5 }true
!= 或 ne不等于${ 5 !=5 } 或 ${ 5 ne 5 }false
< 或 lt小于${ 3 < 5 } 或 ${ 3 lt 5 }true
> 或 gt大于${ 2 > 10 } 或 ${ 2 gt 10 }false
<= 或 le小于等于${ 5 <= 12 } 或 ${ 5 le 12 }true
>= 或 ge大于等于${ 3 >= 5 } 或 ${ 3 ge 5 }false
  1. 逻辑运算
逻辑运算符说 明范 例结果
&& 或 and与运算${ 12 == 12 && 12 < 11 } 或 ${ 12 == 12 and 12 < 11 }false
|| 或 or或运算${ 12 == 12 || 12 < 11 } 或 ${ 12 == 12 or 12 < 11 }true
! 或 not取反运算${ !true } 或 ${not true }false
  1. 算数运算
算数运算符说 明范 例结果
+加法${ 12 + 18 }30
-减法${ 18 - 8 }10
*乘法${ 12 * 12 }144
/ 或 div除法 144 / 12 或 { 144 / 12 }或 144/12{ 144 div 12 }12
% 或 mod取模KaTeX parse error: Expected '}', got 'EOF' at end of input: { 144 % 10 }或{ 144 mod 10 }4
  1. empty 运算

empty 运算可以判断一个数据是否为空,如果为空,则输出true,不为空输出false。

以下几种情况为空:

  1. 值为null 值的时候,为空

  2. 值为空串的时候,为空

  3. 值是Object 类型数组,长度为零的时候

  4. list 集合,元素个数为零

  5. map 集合,元素个数为零

<%
      String str ="";
      Object obj = null;
      List list=  new ArrayList();
      Map map = new HashMap();
      Object[] arrObj = new Object[]{};
      int[] arrInt= new int[]{};
      request.setAttribute("str",str);
      request.setAttribute("obj",obj);
      request.setAttribute("list",list);
      request.setAttribute("map",map);
      request.setAttribute("arrObj",arrObj);
    request.setAttribute("arrInt",arrInt);
  %>
<%--    true--%>
    ${empty str}<br/>
    <%--    true--%>
  ${empty obj}<br/>
    <%--    true--%>
  ${empty list}<br/>
    <%--    true--%>
  ${empty map}<br/>
<%--    false--%>
  ${empty arrInt} <br/>
    <%--    true--%>
    ${empty arrObj} <br/>
  </body>
  1. 三元运算

表达式1?表达式2:表达式3

如果表达式1 的值为真,返回表达式2 的值,如果表达式1 的值为假,返回表达式3 的值。

  ${5==5?"true":"false"}
  1. “.”点运算和[] 中括号运算符

.点运算,可以输出Bean 对象中某个属性的值。

[]中括号运算,可以输出有序集合中某个元素的值。

并且[]中括号运算,还可以输出map 集合中key 里含有特殊字符的key 的值。

  爱好:${person.hoby['basketball']}//此时的key必须加上单引号

表达式的11 个隐含对象

EL 个达式中11 个隐含对象,是EL 表达式中自己定义的,可以直接使用。

隐含对象类型说明
PageContextPageContextImpl它可以获取jsp 中的九大内置对象
PageScopeMap<String,Object>它可以获取pageContext 域中的数据
RequestScopeMap<String,Object>它可以获取Request 域中的数据
sessionScopeMap<String,Object>它可以获取Session 域中的数据
applicationScopeMap<String,Object>它可以获取ServletContext 域中的数据
paramMap<String,String>它可以获取请求参数的值
paramValuesMap<String,String[]>它也可以获取请求参数的值,获取多个值的时候使用。
headerMap<String,String>它可以获取请求头的信息
headerValuesMap<String,String[]>它可以获取请求头的信息,它可以获取多个值的情况
cookieMap<String,Cookie>它可以获取当前请求的Cookie 信息
initParamMap<String,String>它可以获取在web.xml 中配置的上下文参数
http://localhost:8080/index.jsp?username=admin
${param.username}

pageContext 对象的使用

  1. 协议:

  2. 服务器ip:

  3. 服务器端口:

  4. 获取工程路径:

  5. 获取请求方法:

  6. 获取客户端ip 地址:

  7. 获取会话的id 编号:

 <%--
        request.getScheme() 它可以获取请求的协议
        request.getServerName() 获取请求的服务器ip 或域名
        request.getServerPort() 获取请求的服务器端口号
        getContextPath() 获取当前工程路径
        request.getMethod() 获取请求的方式(GET 或POST)
        request.getRemoteHost() 获取客户端的ip 地址
        session.getId() 获取会话的唯一标识
    --%>
    <%
      pageContext.setAttribute("req", request);
    %>
    <%=request.getScheme() %> <br>
  <hr/>
    1.协议: ${ req.scheme }<br>
    2.服务器ip:${ pageContext.request.serverName }<br>
    3.服务器端口:${ pageContext.request.serverPort }<br>
    4.获取工程路径:${ pageContext.request.contextPath }<br>
    5.获取请求方法:${ pageContext.request.method }<br>
    6.获取客户端ip 地址:${ pageContext.request.remoteHost }<br>
    7.获取会话的id 编号:${ pageContext.session.id }<br>

EL 表达式其他隐含对象的使用

param Map<String,String> 它可以获取请求参数的值

paramValues Map<String,String[]> 它也可以获取请求参数的值,获取多个值的时候使用。

示例代码:

输出请求参数username 的值:${ param.username } <br> 
输出请求参数password 的值:${ param.password } <br> 
输出请求参数username 的值:${ paramValues.username[0] } <br>
输出请求参数hobby 的值:${ paramValues.hobby[0] } <br> 
输出请求参数hobby 的值:${ paramValues.hobby[1] } <br>

请求地址:

http://localhost:8080/09_EL_JSTL/other_el_obj.jsp?username=wzg168&password=666666&hobby=java&hobby=cpp

header Map<String,String> 它可以获取请求头的信息

header Values Map<String,String[]> 它可以获取请求头的信息,它可以获取多个值的情况

示例代码:

输出请求头【User-Agent】的值: h e a d e r [ ′ U s e r − A g e n t ′ ] < b r > 输 出 请 求 头 【 C o n n e c t i o n 】 的 值 : { header['User-Agent'] } <br> 输出请求头【Connection】的值: header[UserAgent]<br>Connection{ header.Connection }
输出请求头【User-Agent】的值:${ headerValues[‘User-Agent’][0] }

cookie Map<String,Cookie> 它可以获取当前请求的Cookie 信息

示例代码:

获取Cookie 的名称:${ cookie.JSESSIONID.name } <br> 
获取Cookie 的值:${ cookie.JSESSIONID.value } <br>

initParam Map<String,String> 它可以获取在web.xml 中配置的上下文参数

web.xml 中的配置:

<context-param>    
    <param-name>username</param-name>    
    <param-value>root</param-value>
</context-param> 
<context-param>    
    <param-name>url</param-name>    
    <param-value>jdbc:mysql:///test</param-value> 
</context-param>

示例代码:

输出<Context-param>username 的值:${ initParam.username } <br> 
输出<Context-param>url 的值:${ initParam.url } <br>

JSTL 标签库(重点)

JSTL 标签库全称是指JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的JSP 标签库。

EL 表达式主要是为了替换jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个jsp 页面变得更佳简洁。

JSTL 由五个不同功能的标签库组成

功能范围URI前缀
核心标签库–重点http://java.sun.com/jsp/jstl/corec
格式化http://java.sun.com/jsp/jstl/fmtfmt
函数http://java.sun.com/jsp/jstl/functionsfn
数据库(不使用)http://java.sun.com/jsp/jstl/sqlsql
XML(不使用)http://java.sun.com/jsp/jstl/xmlx

使用

导包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WUvOu8Qd-1617617768848)(assets/image-20210403141607314.png)]

引入所要使用的标签库

<%--      引入所要使用的标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--格式化库--%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%--函数库--%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

core 核心库使用

<c:set />(使用很少)
<%--    作用:set 标签可以往域中保存数据
    域对象.setAttribute(key,value);
    scope 属性设置保存到哪个域
    page 表示PageContext 域(默认值)
    request 表示Request 域
    session 表示Session 域
    application 表示ServletContext 域
    var 属性设置key 是多少
    value 属性设置值
    --%>
    <c:set  scope="request" value="admin" var="user" />
    ${user}
<c:if />
 <c:set var="sex" value="0" scope="request"/>
    <c:if test="${sex == 1}">
        <h4></h4>
    </c:if>
    <c:if test="${sex == 0}">
        <h4></h4>
    </c:if>

注意:没有c:else

<c:choose> <c:when> <c:otherwise>标签
 <c:set var="age" scope="request" value="2"/>
  <c:choose>
      <c:when test="${age > 18 && age < 30}">
          成年人
      </c:when>
      <c:when test="${age > 30}">
          中年人
      </c:when>
      <c:otherwise>
          <c:choose>
              <c:when test="${age > 0 && age<3}">
                  婴幼儿
              </c:when>
          </c:choose>
      </c:otherwise>
  </c:choose>
<c:forEach />
  <c:forEach var="i" begin="0" end="10" step="2">
      <h5>${i}</h5>
  </c:forEach>
  <c:forEach var="i" begin="0" end="10" step="2">
      <h5>${i}</h5>
  </c:forEach>
<%--遍历集合list  items就是需要遍历的集合对象或集合属性--%>
<c:forEach items="${person.citys}" var="city">
    <h5>${city}</h5>
</c:forEach>
<%--  遍历集合Map--%>
  <c:forEach items="${person.hoby}" var="entity">
      <h5>${entity.key}---${entity.value}</h5>
  </c:forEach>

页面jsp 动态化(零点读书)

将页面的扩展名改为.jsp

同时需要为页面添加page指令

	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	
	<%;
		String basePath = request.getScheme()+"://" + request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
	%>
	<base href="<%=basePath%>">

将页面的公共部分 单独列出来

<jsp:include page="/pages/public/foot.jsp"/>
<jsp:include page="/pages/public/top.jsp"/>

登录,注册错误提示,及表单回显

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3wq55sgR-1617617768852)(assets/image-20210403155044290.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZxNKw95-1617617768855)(assets/image-20210403155115440.png)]

后端代码的优化

一个servlet处理多个请求

页面使用隐藏域来传递请求的真正的方法


<input type="hidden" name="_method" value="login">
public class UserServlet extends HttpServlet {
    private IUserService userService = new UserServiceImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("_method");
        if("login".equals(method)){
            login(req,resp);
        }else if("regist".equals(method)){
            regist(req,resp);
        }
    }
    public void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 接收用户输入的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = userService.login(username,password);
        System.out.println("user = " + user);
        if(user!=null){
            req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
        }else{
            //當用戶輸入的 用戶名密碼錯誤時 需要給出明確的提示
            req.setAttribute("errorMsg","用戶名或密碼錯誤");
            req.setAttribute("username",username);
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
        }
    }
    public void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username= req.getParameter("username");
        String password = req.getParameter("password");
        String email = req.getParameter("email");
        User user = new User(username,password,email);
        userService.save(user);
        req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
    }
}

在以上的代码中 由于可能会存在大量的if…else 为了减少判断 再此使用反射来优化代码

 @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("_method");
        try {
          Method method1=   this.getClass().getDeclaredMethod(method,HttpServletRequest.class,HttpServletResponse.class);
          method1.invoke(this,req,resp);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

为了减少代码的冗余 将上述代码抽取出来 单独形成一个baseServlet

public abstract class BaseServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("_method");
        try {
            Method method1=   this.getClass().getDeclaredMethod(method,HttpServletRequest.class,HttpServletResponse.class);
            method1.invoke(this,req,resp);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

此时我们的自定以servlet只需要去继承BaseServlet

public class UserServlet extends BaseServlet {
    private IUserService userService = new UserServiceImpl();

    public void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 接收用户输入的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = userService.login(username,password);
        System.out.println("user = " + user);
        if(user!=null){
            req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
        }else{
            //当用户输入的用户名或密码错误时,需要给出明确地提示
            req.setAttribute("errorMsg","用戶名或密码错误");
            req.setAttribute("username",username);
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
        }
    }
    public void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username= req.getParameter("username");
        String password = req.getParameter("password");
        String email = req.getParameter("email");
        User user = new User(username,password,email);
        userService.save(user);
        req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值