IDEA配置Web开发环境&Servlet

  • 2019-05-03
  • 979
  • 0

下载安装Tomcat

解压到指定目录,配置好JAVA_HOME,CATALINA_HOME(值tomcat所在目录,bin的上一级全路径,后面不要到分号和正反斜杠\或/)系统变量,双击tomcat目录下bin目录下的startup.bat批处理文件启动即可,浏览器测试,http://localhost:8080有界面说明正常。

CATALINA_HOME => D:\software\apache-tomcat-7.0.94

IDEA Console乱码问题

IDEA安装目录

D:\software\IntelliJ IDEA 2019.1.1\bin\idea64.exe.vmoptions
添加一句
-Dfile.encoding=UTF-8

idea部署的项目不在Tomcat的webapps目录下面?

intellij idea使用Tomcat部署项目后并不会把编译后的项目复制到tomcat的webapps目录下,但是它会把编译好的项目路径告诉Tomcat,让Tomcat来找到这个项目,编译目录的位置也是可以设置的file>Project Constructions>Project Setting>modules

在out目录下,

  • artifacts: web文件夹生成的目录
  • production: 编译目录

创建Web工程

file>new>Project>java 选中右侧Java EE下Web Application,next>项目名字。

导入tomcat自带jar包

file>Project Structue>modules>Depencenites>右侧+>JARS or directories>Libraries>Application Server Libraryes>Add Selected>Applay 导入全部,右侧Privide改成Compile。

自己的jar包,在web/WEB-INF/lib  新建一个lib放里面

IDEA配置Tomcat

run>Edit Configurations>选择自己的版本即可,VM options加个-Dfile.encoding=UTF-8

servlet是什么?

其实就是一个java程序,运行在我们的web服务器上,用于接收和响应 客户端的http请求。 更多的是配合动态资源来做。 当然静态资源也需要使用到servlet,只不过是Tomcat里面已经定义好了一个 DefaultServlet

配置Servlet

src下新建Package com.husaky.servlet>新建HelloServlet.java,因为Servlet是一个接口,我们只需要用到部分方法,而必须要重写所有方法,所以我们可以继承HttpServlet这个Servlet实现类,这个类主要用于处理http请求,继承httpservlet 重写doGet doPost方法就可以了

package com.husaky.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class HttpServletConfig extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get a request use get method");
        // servletConfig可以获取servlet在配置里面的一些信息
        // 1得到servlet配置对象,专门用于在配置servlet的信息
        ServletConfig config = getServletConfig();

        // 获取到的是配置servlet里面servlet-name的文本内容
        String servletName = config.getServletName();
        System.out.println("servletName=" + servletName);

        // 可以获取具体的初始化参数
        String address = config.getInitParameter("addresss");
        System.out.println("address=" + address);

        // 获取所有的参数名称
        Enumeration<String> names = config.getInitParameterNames();
        while (names.hasMoreElements()) {
            String key = (String)names.nextElement();
            String value = config.getInitParameter(key);
            System.out.println("key==" +key+"value=="+value);
        }
    }

}

在web/WEB-INF/web.xml里面配置一下servlet规则,这里面配置了,也就是init-param内的信息

ServletConfig

<servlet>
        <servlet-name>HttpServlet</servlet-name>
        <servlet-class>com.husaky.servlet.HttpServlet</servlet-class>

        <!--        添加初始化参数-->
        <init-param>
            <param-name>address</param-name>
            <param-value>guangdong</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>HttpServlet</servlet-name>
        <url-pattern>/sc</url-pattern>
    </servlet-mapping>

浏览器localhost:8080/HelloServlet/sc,控制台会输出doGet设置的获取xml配置的信息

url-pattern有大致三种设置方式

  •  全路径匹配

以 / 开始   /a /aa/bb, localhost:8080/项目名称/aa/bb 

  • 路径匹配 , 前半段匹配

以  / 开始 , 但是以 * 结束  /a/* /*  ,* 其实是一个通配符,匹配任意文字,localhost:8080/项目名称/aa/bb 

  • 以扩展名匹配

没有/  以 * 开始   *.扩展名    *.aa *.bb 

执行流程分析

  1. 找到tomcat应用
  2. 找到项目
  3. 找到项目下的web.xml,然后在里面找到url-pattern,看有没有哪一个pattern的内容是a
  4. 找到servlet-mapping中的那个servlet-name
  5. 找到上面定义的servlet元素中的servlet-name中的HelloServlet
  6. 找到下面定义的servlet-class然后创建该类的实例
  7. 继而执行该实例的service方法

servlet生命周期

从创建到销毁,所调用的那些方法。

init方法

  • 在创建该servlet的实例时,就执行该方法。一个servlet只会初始化一次, init方法只会执行一次,默认情况下是 : 初次访问该servlet,才会创建实例。 

service方法

  • 只要客户端来了一个请求,那么就执行这个方法了。该方法可以被执行很多次。 一次请求,对应一次service方法的调用

destroy方法

  • servlet销毁的时候,就会执行该方法,该项目从tomcat的里面移除,正常关闭tomcat就会执行 shutdown.bat

默认情况下,只有在初次访问servlet,才会执行init方法,有时候,我们可能需要在这个方法里面执行一些初始化工作,甚至做一些耗时的逻辑,那么这个时候,初次访问,可能会在init方法中逗留时间太久,那可以在配置web.xml的时候,使用<load-on-start>2</load-on-startup>来制定,给定的数字越小,启动时机越早,一般不写负数,从2开始即可

 <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.husaky.servlet.HelloServlet</servlet-class> 全路径
        <load-on-startup>2</load-on-startup>
    </servlet>

ServletConfig作用

  1. 以后我们自己开发的一些应用,使用到了一些技术,或者一些代码,自己不会,但是有人写出来了,它的代码放置在了自己的servlet类里面,
  2. 刚好这个servlet里面需要一个数字或者变量值,但是这个值不能固定了,所以要求使用到这个servlet的公司,在注册servlet的时候,必须要在web.xml里面声明init-params
  3. 这个其实用的频率不高,如果有参数才会用

ServletContext

 Servlet 上下文,每个web工程都只有一个ServletContext对象。 说白了也就是不管在哪个servlet里面,获取到的这个类的对象都是同一个。使用频率很高。

作用:

  1. 获取全局配置参数

<!--    全局参数-->
    <context-param>
        <param-name>addresss</param-name>
        <param-value>广州</param-value>
    </context-param>


-----------------------------------
  @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取对象
        ServletContext context = getServletContext();
        String address = context.getInitParameter("address");
        System.out.println("address="+address);
    }

  1. 获取web工程中的资源

方式一:不行

新建src/config.properties文件,普通方式读取这个配置文件

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = new FileInputStream("config.properties");
        Properties ps = new Properties();
        ps.load(is);
        String name = ps.getProperty("name"); //获取不到的
     
    }

   如果想获取web工程下的资源,用普通的方法是不行的,因为路径不对,这里是相对路径,其实是根据jre来确定的,但是我们这是一个web工程,jre后面会由tomcat管理,所以这里真正的相对路径是tomcat里面的bin目录。

方式二:可行

public class HelloHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = getServletContext();
        String path = context.getRealPath("");
        // 获得编译后的路径,E:\servletTest\out\artifacts\servletTest_war_exploded
        // 我的config.properties放在src下,注意了


        Properties ps = new Properties();
//        String confPath1 = path + "\\WEB-INF\\classes\\com\\husaky\\servlet\\config.properties";
        // 这两周方式都可以
        String confPath2 = context.getRealPath("WEB-INF\\classes\\com\\husaky\\servlet\\config.properties");
        InputStream is = new FileInputStream(confPath2);
        ps.load(is);
        String name = ps.getProperty("name");
        System.out.println("获取到配置文件的名字是=="+name);

        // 还可以通过这种方法直接省略InputStream
//        InputStream is2 = context.getResourceAsStream("WEB-INF\\classes\\com\\husaky\\servlet\\config.properties");
    }

方式三:可行

  /**
     * 通过classLoader去获取工程下的资源,类加载器
     */
    private void test3() {
        try {
            //classLoader 对应的是E:\servletTest\out\artifacts\servletTest_war_exploded\WEB-INF\classes
            Properties ps = new Properties();
            // 获取该java文件的class,然后获取到加载这个class到虚拟机中的那个类加载对象
            InputStream is =
                    this.getClass()
                            .getClassLoader()
                            .getResourceAsStream("com\\husaky\\servlet\\config.properties");
            ps.load(is);
            String name = ps.getProperty("name");
            System.out.println("name by classLoader=="+name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  1. 存取数据,servlet间共享数据  域对象

 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 校验数据
        // 向客户端输出内容
        PrintWriter pw = resp.getWriter();
        if ("admin".equals(username) && "123".equals(password)) {
            Object obj = getServletContext().getAttribute("count");
            int totalCount = 0;
            if (obj != null) {
                totalCount = (int)obj;
            }
            getServletContext().setAttribute("count", totalCount + 1);

            // 跳转
            resp.setStatus(302);
            resp.setHeader("Location", "success.html");
            // success.html界面有一个超链接,跳转到count.html,展示当前登录的总次数,可以在这个countServlet里面获取totalCount
        } else {
            pw.write("login failed..");
        }
    }


--------------------------------------------------
public class CountServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int totalCount = (int)getServletContext().getAttribute("count");
        PrintWriter pw = resp.getWriter();
        pw.write("loging success count=="+totalCount);
    }

}

ServletContext生命周期

服务器启动的时候,会为托管的每一个web应用程序,创建一个ServletContext对象,从服务器移除托管,或者是关闭服务器。 

ServletContext作用范围

只要在这个项目里面,都可以取。 只要同一个项目。 A项目 存, 在B项目取,是取不到的? ServletContext对象不同。

HttpServletRequest

获取请求头信息

 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //枚举集合
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = (String)headerNames.nextElement();
            String value = req.getHeader(name);
            System.out.println(name +"=="+ value);
        }
    }

获取提交的数据

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取客户端提交上来的数据
        String name = req.getParameter("name");
        System.out.println("name="+name);

        // 获取到所有的参数,得到一个枚举集合
        //Enumeration<String> parameterNames = req.getParameterNames();

        Map<String, String[]> map =req.getParameterMap();
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = (String) iterator.next();
            String value = map.get(key)[0];
            String value1 = map.get(key)[1];
            String value2 = map.get(key)[2];

            System.out.println(key+"==="+ value + "="+ value1 + "=" + value2);
        }


    }

get请求提交中文数据乱码问题

 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("name");
        String password = req.getParameter("pass");

        // get请求过来的数据,在url地址栏上就已经编码了,我们取到的中文数据就是乱码
        //tomcat收到了数据,getParameter默认使用ISO-8859-1去解码

        // 先让文字回到ISO-8859-1对应的字节数组,然后在拼接utf8字符串
        username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
        System.out.println(username);

        // 还可以在tomcat里面做配置,tomcat/conf/server.xml => 搜8080
        //   <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIIEncoding="UTF-8" />
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

post请求提交中文数据乱码问题

设置请求体里面的文字编码。 
        request.setCharacterEncoding(“UTF-8”);
 这行设置一定要写在getParameter之前。 get方式用这行没用

HttpServletResponse

 负责返回数据给客户端, 输出数据到页面上

//以字符流的方式写数据
response.getWriter().write(“<h1>hello response…</h1>”);

//以字节流的方式写数据 
response.getOutputStream().write(“hello response2222…”.getBytes());

以字符流输出

response.getWriter()


		//1. 指定输出到客户端的时候,这些文字使用UTF-8编码
		response.setCharacterEncoding("UTF-8");
		
		//2. 直接规定浏览器看这份数据的时候,使用什么编码来看。
		response.setHeader("Content-Type", "text/html; charset=UTF-8");
		
		response.getWriter().write("这是服务端返回内容");

 以字节流输出 

response.getOutputStream()


	
		
		//1. 指定浏览器看这份数据使用的码表
		response.setHeader("Content-Type", "text/html;charset=UTF-8");
		
		//2. 指定输出的中文用的码表
		response.getOutputStream().write("这是字节流服务端返回内容".getBytes("UTF-8"));

不管是字节流还是字符流,直接使用一行代码就可以了。

response.setContentType("text/html;charset=UTF-8");

	然后在写数据即可。

文件下载

1. 直接以超链接的方式下载,不写任何代码。 也能够下载东西下来。 

web/test.html

<!--让tomcat的默认servlet去提供下载:<br>-->
<a href="download/aa.jpg">aa.jpg</a><br>
<a href="download/bb.txt">bb.txt</a><br>
<a href="download/cc.rar">cc.rar</a><br>

http://localhost:8080/项目名/test.html,点击a链接即可下载。原因是tomcat里面有一个默认的Servlet — DefaultServlet 。这个DefaultServlet 专门用于处理放在tomcat服务器上的静态资源。

2.手动处理下载文件

<a href="down?filename=aa.jpg">aa.jpg</a><br>
<a href="down?filename=bb.txt">bb.txt</a><br>
<a href="down?filename=cc.rar">cc.rar</a><br>

----------------------------------
  <servlet-name>HttpServletDemo</servlet-name>
        <servlet-class>com.husaky.HttpServletDemo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HttpServletDemo</servlet-name>
        <url-pattern>/down</url-pattern>
    </servlet-mapping>

-----------------------------------
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取要下载的文件名字
        String fileName = req.getParameter("filename");
        // 获取这个文件在tomcat里面的绝对路径
        String path = getServletContext().getRealPath("download/"+fileName);
        // 让浏览器受到这份资源的时候,以下载的方式提醒用户,而不是直接展示
        resp.setHeader("Content-Disposition", "attachment;filename="+fileName);
        // 转化成输入流
        InputStream is = new FileInputStream(path);
        OutputStream os = resp.getOutputStream();
        
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        os.close();
        is.close();
    }

3.下载的文件包含中文名称

 针对浏览器类型,对文件名字做编码处理 Firefox (Base64) , IE、Chrome … 使用的是URLEncoder

 * 如果文件的名字带有中文,那么需要对这个文件名进行编码处理
		 * 如果是IE ,或者  Chrome (谷歌浏览器) ,使用URLEncoding 编码
		 * 如果是Firefox , 使用Base64编码
		 */
		//获取来访的客户端类型
		String clientType = request.getHeader("User-Agent");
		
		if(clientType.contains("Firefox")){
			fileName = DownLoadUtil.base64EncodeFileName(fileName);
		}else{
			//IE ,或者  Chrome (谷歌浏览器) ,
			//对中文的名字进行编码处理
			fileName = URLEncoder.encode(fileName,"UTF-8");
		}

请求转发和重定向

1.重定向

  1. 地址上显示的是最后的那个资源的路径地址
  2.  请求次数最少有两次, 服务器在第一次请求后,会返回302 以及一个地址, 浏览器在根据这个地址,执行第二次访问。
  3. 可以跳转到任意路径。 不是自己的工程也可以跳。
  4. 效率稍微低一点, 执行两次请求。 
  5. 后续的请求,没法使用上一次的request存储的数据,或者 没法使用上一次的request对象,因为这是两次不同的请求

/*
			之前的写法
			response.setStatus(302);
			response.setHeader("Location", "login_success.html");*/
			
			//重定向写法: 重新定位方向 参数即跳转的位置
		response.sendRedirect("login_success.html");

2.请求转发

  1. 地址上显示的是请求servlet的地址。  返回200 ok
  2. 请求次数只有一次, 因为是服务器内部帮客户端执行了后续的工作。 
  3. 只能跳转自己项目的资源路径 。  
  4. 效率上稍微高一点,因为只执行一次请求。 
  5. 可以使用上一次的request对象。 

//请求转发的写法: 参数即跳转的位置
		request.getRequestDispatcher("login_success.html").forward(request, response);

评论

还没有任何评论,你来说两句吧

粤ICP备17155863号

- 友情链接 - Theme by Qzhai