JavaWeb
Servlet学习结构
1.JavaWeb基本概念
1.1 web静态和动态
-
静态web
HTML,CSS,提供所有的数据是不会变化的。 缺点:1.web界面无法动态更新,所有用户看到一个界面 2.无法与数据库交互
-
动态web
动态web如淘宝等网站,会根据自己的账号登录,看见自己的信息。 缺点:1.如果服务器崩溃,可能出现停机 2.可以与数据库交互(注册,登录,信息变化)
2.Web服务器
2.1 了解
ASP: 微软:国内最早流行的就是ASP; 1.在HTML中嵌入了VB的脚本,ASP+COM; 2.在ASP开发中,基本一个页面都有几干行的业务代码,页面极其换乱 3.维护成本高! 4.C# 5.IIS php: 1.PHP开发速度很快,功能很强大,跨平台,代码很简单(70%,WP) 2.无法承载大访问量的情况(局限性) jSP/Servlet: 1.B/S;浏览和服务器 2.C/S:客户端和服务器 sun公司主推的B/S架构 基于Java语言的(所有的大公司,或者一些开源的组件,都是用Java写的) 可以承载三高问题带来的影响; 语法像ASP,ASP->JSP,加强市场强度;
2.2 tomcat
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息; lIS 微软的;ASP,Windows中自带的
Tomcat服务器
Tomcat是Apache 软件基金会(Apache Software Foundation)的jakarta项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat中得到体现,因为Tomcat 技术先进、性能稳定,而且免费,因而深受lava爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。 tomcat就是运行java程序,提供api接口。
安装步骤
1.官网下载并安装:Apache Tomcat® - Welcome! 2.解压tomcat文件,并在解压目录下bin --> startup.bat,双击运行 3.tomcat默认端口8080,在浏览器访问localhost:8080
问题: 1.Java环境没有配置 2.闪出问题:需要配置兼容性 3.乱码问题:配置文件修改:conf-->logging.properties-->java.util.logging.ConsoleHandler.encoding = GBK
了解配置文件和目录
1.目录 1.1 bin-->启动和关闭脚本 1.2 conf-->配置 1.3 lib-->依赖jar包 1.4 webapps-->项目
2.配置文件 2.1 配置端口号(tomcat:8080 mysql:3306 http:80 https:443) 2.2 配置主机名称(这里需要修改电脑配置localhost:C:\Windows\System32\drivers\etc\hosts) 2.3 配置应用项目:webapps
tomcat作用
就是一个服务器。
2.3 网站如何经行访问
检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射; 1.有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问 2.没有:去DNS服务器找,找到的话就返回,找不到就返回找不到;
3. Http
(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。 文本:html,字符串,… 超文本:图片,音乐,视频,定位,地图.…… 端口:80
-
http1.0
-
HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接
-
-
http2.0
-
HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源。
-
3.1 Http请求
Request URL:https://www.baidu.com/ 请求地址 Request Method:GET get方法/post方法 Status Code:200 OK 状态码:200 Remote(远程) Address:14.215.177.39:443 Accept:text/html 告诉浏览器,它所支持的数据类型 Accept-Encoding:支持哪种编码格式 Accept-Language:zh-CN,zh;q=0.9 语言 Cache-Control:缓存控制 Connection:keep-alive
-
请求行 1.请求方式:get/post get请求参数有限制,会在浏览器显示数据,不安全 post请求参数不限,不会在浏览器显示数据,安全
-
请求头 1.支持的数据类型 2.支持哪种编码格式等等
3.2 http响应
-
响应体
Accept:告诉浏览器,它所支持的数据类型 Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1 Accept-Language:告诉浏览器,它的语言环境 Cache-Control:缓存控制 Connection:告诉浏览器,请求完成是断开还是保持连接 HOST:主机..../. Refresh:告诉客户端,多久刷新一次; Location:让网页重新定位;
-
响应状态码
200 请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。 400 语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。 401 当前请求需要用户验证,一般表示权限不足的意思。 404 请求失败,请求所希望得到的资源未被在服务器上发现。 405 请求行中指定的请求方法不能被用于请求相应的资源。 500 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。
4. Maven
Apache Maven是一个(特别是Java编程)项目管理及自动构建工具,由Apache软件基金会所提供。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。Maven核心思想约定大于配置。
安装教程网站:B站---【狂神说Java】JavaWeb入门到实战---笔记夜里的雨的博客-CSDN博客狂神说javaweb笔记 视频教程网站:javaweb-05:Maven环境搭建哔哩哔哩bilibili
1.下载Maven,官网:https://maven.apache.org/ 2.配置环境变量 3.修改配置文件(settings.xml):阿里云镜像 <mirror> <id>nexus-aliyun</id> <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> 4.配置自己的本地仓库 <localRepository>D:\repository</localRepository>
5. 第一个HelloWorld
HttpServlet类需要导入依赖两种方式: 1.直接在pom.xml中配置 <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> </dependencies> 2.提前配置tomcat.tomcat依赖有servlet依赖
HelloWord
第一步:继承HttpServlet抽象类 第二步:配置Mapping映射
public class HelloWorldServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 响应流
PrintWriter printWriter=resp.getWriter();
printWriter.write("Hello World !");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req,resp);
}
}
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.demo.HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Servlet原理分析(狂神说)
5.1 Mapping映射问题
1.一个Servlet可以指定一个映射路径 2.一个servlet可以指定多个映射路径 <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/hello1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/hello2</url-pattern> </servlet-mapping> 3.一个servlet可以指定通用映射路径 <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping> 4.指定一些后缀或者前缀等等… <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> 5./*与/具体路径 相比,/具体路径优先于/*,所以可以根据这个来制作404找不到网页设计。 <!--404--> <servlet> <servlet-name>error</servlet-name> <servlet-class>com.kuang.servlet.ErrorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>error</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
6.Servlet
Servlet简介
Servlet 是 Server Applet 的缩写,译为“服务器端小程序”,是一种使用 Java 语言来开发动态网站的技术。 Servlet 虽然被称作“小程序”,但是它的功能却异常强大,因为它是基于 Java 的,几乎可以使用所有的 Java API,Java 能做的事情,Servlet 也能做。 您可以这样理解,Servlet 是 Sun 公司推出的一种基于 Java 的动态网站开发技术。 严格来说,Servlet 只是一套 Java Web 开发的规范,或者说是一套 Java Web 开发的技术标准。 只有规范并不能做任何事情,必须要有人去实现它。所谓实现 Servlet 规范,就是真正编写代码去实现 Servlet 规范提到的各种功能,包括类、方法、属性等。
6.1 创建Servlet的方式
方式一:实现Servlet接口
我们通过实现Servlet 接口里的方法,就可以开发出动态网页。代码如下: public class TestServlet implements Servlet { 在这里去实现方法 }
方式二:继承HttpServlet
直接实现 Servlet 接口比较麻烦,需要实现很多方法,所以 Servlet 规范又提供了两个抽象类,分别是GenericServlet 类和 HttpServlet 类, 它们都实现了 Servlet 接口的很多常用功能。和 GenericServlet 类相比,HttpServlet 类更加方便,所以实际开发中一般都继承自 HttpServlet 类。 我们也可以通过 继续 HttpServlet 类来创建Servlet,代码如下: public class MyHttpTestServlet extends HttpServlet { 重写我们需要用到的方法,如: doGet().. 专门用于接收get请求 doPost().. 专门用于接收post请求 } 因为这种方式更简洁,所有更推荐使用这种方式来创建Servlet
6.2 ServletContext上下文对象
Servlet 容器启动时,会为当前项目创建一个唯一的 ServletContext 对象,该对象一般被称为“Servlet 上下文”。 这是一个全局对象,在每个Servlet里面都可以使用,而且使用ServletContext对象它的范围是Servlet容器里面(限于Servlet类), 我们在于ServletContext里面的数据就被保护于Servlet容器之中。
获取ServletContext对象
1. 通过 GenericServlet 提供的 getServletContext() 方法,HttpServlet继承GenericServlet即也有该方法 2. 通过 Servlet接口提供的getServletConfig()返回的对象的getServletContext() 方法
ServletContext对象用处
1.共享数据,每一个Servlet都可以通过ServletContext共享容器中的数据。 2.获取初始化参数,在xml文件中,利用context-param标签,设置初始化参数。 3.请求转发,context.getRequestDispatcher("/gp").forward(req,resp); 4.读取资源文件,getServletContext.getResourceAsStream("xxxxx"); * 1. Class.getResourceAsStream(String path) : * path 不以'/'开头时默认是从此类所在的包下取资源,以'/'开头则是从ClassPath(Src根目录)根下获取。 * 其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。 * 2. Class.getClassLoader.getResourceAsStream(String path) : * 默认则是从ClassPath根下获取,path不能以'/'开头,最终是由ClassLoader获取资源。 * * 3. ServletContext. getResourceAsStream(String path): * 默认从WebAPP根目录下取资源,Tomcat下path是否以’/'开头无所谓,当然这和具体的容器实现有关。
网页浏览人数记录
@WebServlet("/getNumber")
public class BrowsePageOneServlet implements Servlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig=servletConfig;
System.out.println("Servlet初始化......");
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
//根据servletConfig获取servletContent
ServletContext servletContext=servletConfig.getServletContext();
visitorNumber(servletContext);
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("Servlet销毁了......");
}
public static void visitorNumber(ServletContext servletContext){
//获取xml文件的初始化参数
Integer count= servletContext.getAttribute("count")==null
?null:Integer.parseInt(servletContext.getAttribute("count").toString());
if(count==null){
count=Integer.parseInt(servletContext.getInitParameter("count"));
}else{
count= Integer.parseInt(servletContext.getAttribute("count").toString());
}
//注意自增,容易出错
servletContext.setAttribute("count",++count);
System.out.println("访问过的人数:"+count);
}
}
@WebServlet("/getNumber1")
public class BrowsePageTwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
BrowsePageOneServlet.visitorNumber(getServletContext());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req,resp);
}
}
文件读取
@WebServlet("/getNumber1")
public class BrowsePageTwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 通过servletContent获取db.properties文件
InputStream resourceAsStream1 = getServletContext().getClassLoader().getResourceAsStream("db.properties");
try{
byte[] bytes=new byte[1024];
StringBuffer sb=new StringBuffer();
int i;
do{
i=resourceAsStream1.read(bytes);
if(i>-1){
sb.append(new String(bytes,0,i));
}
}while (i>-1);
resourceAsStream1.close();
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req,resp);
}
}
6.3 HttpServletRequest
一般情况下,浏览器通过HTTP协议来访问服务器的资源,Servlet主要用来处理这些HTTP请求。 1.Servlet容器收到来自客户端的HTTP请求后,容器会针对该每一次请求分别创建一个HttpServletRequest对象和HttpServletResponse对象; 2.HttpServletRequest携带请求相关信息,然后对HTTP进行处理; 3.请求处理完成之后,将响应信息装到HttpServletResponse对象中。 4.Servlet容器将响应信息返回给客户端;
-
请求行信息的方法
@WebServlet("/request")
public class RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// getMethod() 用于获取HTTP请求的方式,返回结果如:GET、POST或者其它
System.out.println(req.getMethod());
// getRequestURI() 用于获取请求行中的资源名称部分,就是位于URL的主机和端口之后,参数之前的那部分。
System.out.println(req.getRequestURI());
// getQueryString() 用于获取请求行中参数部分,就是URL中“?”后面的部分
System.out.println(req.getQueryString());
// getServletPath() 获取Servlet所映射的路径
System.out.println(req.getServletPath());
// getRemoteHost() 用于获取客户端的完整主机名,如果无法解析出客户机的完整主机名,则返回客户机的IP地址
System.out.println(req.getRemoteHost());
// getRemoteAddr() 用于获取客户端IP地址
System.out.println(req.getRemoteAddr());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// getMethod() 用于获取HTTP请求的方式,返回结果如:GET、POST或者其它
System.out.println(req.getMethod());
}
}
-
请求头信息的方法
@WebServlet("/request")
public class RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// getHeader(String name) 用于获取请求头里面的值,参数为请求头的名称
System.out.println(req.getHeader("token"));
// getHeaderNames() 用于获取请求头里面所有名称,返回一个字符串枚举集合
System.out.println(req.getHeaderNames());
// getContentType() 用于获取Content-Type头字段的值(一般用于用于Ajax请求)
System.out.println(req.getContentType());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// getMethod() 用于获取HTTP请求的方式,返回结果如:GET、POST或者其它
System.out.println(req.getMethod());
}
}
-
获取参数或者转发使用
获取参数: getParameter(String name) 获取指定参数名的数值,适用于application/x-www-form-urlencoded类型的参数 getParameterNames() 获取所有参数名称,返回枚举集合 getParameterValues(String name)【弃用】 以字符串数组的形式返回指定参数名的所有参数值,主要合适于checkbox复选框 文件上传: getPart(String name) 获取指定参数名的上传文件,适用于multipart/form-data类型的参数 弃用: getRequestDispatcher(String addr) 其中addr就是给转发器传递的参数,就是表示该转发器要转发到哪个地址 转发器.forward(req, resp) 用于来实现真正的转发
6.4 HttpServletResponse
Servlet容器会针对每次请求创建一个HttpServletResponse对象,并把它作为参数传递给Servlet的doGet或者doPost方法, Servlet处理请求后,会把响应信息装到HttpServletResponse对象中,并由容器解析后返回给客户端。 弃用: 重定向属于客户端行为,服务器在收到客户端请求后,会通知客户端浏览器重新向另外一个新的URL发送请求,这种操作就叫请求重定向。 它本质上就是两次请求,对应的也是两个req对象和两个resp对象。 实现方法: sendRedirect(String url) 该方法可以实现请求的重定向,重定向参数url这个地址
@WebServlet("/response")
public class ResponseTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// setStatus(int status) 用于设置HTTP响应消息的状态码
resp.setStatus(402);
// setContentType(String type) 用于设置Servlet输出内容的MIME类型,以及编码格式
resp.setContentType("application/json");
// getWriter() 用于获取字符输出流对象(PrintWriter),再通过 PrintWriter 对象的 write("输出的文字内容")将内容输出到页面上
resp.getWriter().write("hello world!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req,resp);
}
}
7. 过滤器Filter
过滤器(Filter)是对资源路径进行过滤,决定是放行还是拒绝,或者其它的操作。使用过滤器,可以减少我们的代码开发,使功能更加完善。
Filter创建可以实现Filter接口,xml中配置可以根据Servlet的配置一样来配置,只需跟换Servlet为Filter。
-
配置Filter映射方法(XML、注解)
<filter> <filter-name>filter名称</filter-name> <filter-class>filter类的全路径</filter-class> </filter> <filter-mapping> <filter-name>filter名称</filter-name> <url-pattern>URL地址</url-pattern> </filter-mapping> 优点是可以对整个项目的url一目了然使用@WebFilter("url-pattern")进行配置,该注解是加到我们自己创建的Filter类上面,其中参数就是url-pattern 优点是代码更简洁
简单使用Filter过滤器
@WebFilter("/*")
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化过滤器......");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
//如果是请求携带token就放行
HttpServletRequest httpServletRequest=(HttpServletRequest)servletRequest;
HttpServletResponse httpServletResponse=(HttpServletResponse)servletResponse;
String token = httpServletRequest.getHeader("token");
if(token!=null){
filterChain.doFilter(servletRequest,servletResponse);
}else{
servletResponse.setContentType("text/html;charset=UTF-8");
httpServletResponse.getWriter().write("token未通过!!!");
System.out.println("token未通过!!!");
}
}
@Override
public void destroy() {
System.out.println("过滤器销毁了......");
}
}
在上一个Filter中,用servletRequest.setAttribute(String name, Object o);来添加属性, 然后,再下一个Filter中,用servletRequest.getAttribute(String name); 来获取传递过来的数据 并可以通过filter来设置黑白名单。
8. Listener监听器
监听器Listener是一个实现特定接口的Java类,这个类专门用于监听另一个Java对象的方法调用或者属性改变, 当被监听对象发生上述事件后,监听器就会自动执行某个方法。 1. 事件 Java对象被创建或者销毁、属性被改变的时候触发的事件; 2. 事件源 触发事件的源对象,被监听的对象; 3. 监听器 用于监听事件源对象,事件源对象状态的变化就是触发监听器; 4. 注册监听器 将监听器与事件源进行绑定;
监听器的分类
1. ServletContextListener 用于监听ServletContext对象的创建与销毁 2. ServletContextAttributeListener 用于监听ServletContext对象的属性被更改 3. ServletRequestListener 用于监听ServletRequest对象的创建与销毁 4. ServletRequestAttributeListener 用于监听ServletRequest对象的属性被更改 5. HttpSessionListener 用于监听HttpSession对象的创建与销毁 6. HttpSessionAttributeListener 用于监听HttpSession对象的的属性被更改 7. HttpSessionBindingListener 用于监听JavaBean对象绑定到HttpSession对象,和从HttpSession对象解绑的事件 8. HttpSessionActivationListener 用于监听HttpSession中对象活化和钝化的过程
@WebListener
public class MyListener implements ServletContextListener, ServletContextAttributeListener,
ServletRequestListener, ServletRequestAttributeListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//在这里写一些项目初始化工作的代码
ServletContext context = sce.getServletContext(); //通过ServletContext事件对象获取ServletContext源对象
context.setAttribute("visits", context.getInitParameter("visits")); //将ServletContext初始值中的visits放入ServletContext的属性中
System.out.println("ServletContext创建好了");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//在这里写一些web容器关闭的时候的一些代码,比如一些资源释放等
System.out.println("ServletContext销毁了");
}
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
// System.out.println("ServletContext新增属性了,新增的属性名:" + scae.getName() + ",属性值:" + scae.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
// System.out.println("ServletContext删除属性了,删除的属性名:" + scae.getName() + ",属性值:" + scae.getValue());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
// System.out.println("ServletContext替换属性了,替换的属性名:" + scae.getName() + ",属性值:" + scae.getValue());
}
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
// System.out.println("ServletRequest新增属性了,新增的属性名:" + srae.getName() + ",属性值:" + srae.getValue());
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
// System.out.println("ServletRequest移除属性了,移除的属性名:" + srae.getName() + ",属性值:" + srae.getValue());
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
// System.out.println("ServletRequest替换属性了,替换的属性名:" + srae.getName() + ",属性值:" + srae.getValue());
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
//在这里写一些请求初始化的代码
ServletRequest request = sre.getServletRequest();
try {
request.setCharacterEncoding("utf-8"); //设置请求的字符集编码
} catch (UnsupportedEncodingException exception) {
exception.printStackTrace();
}
// System.out.println("ServletRequest创建好了");
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
//在这里写一些请求执行完毕被销毁的代码
// System.out.println("ServletRequest执行完毕,销毁了");
}
}
9. WebScoket
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebScoket实现步骤
1. 添加依赖 <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>8.0</version> </dependency> 2. 创建一个类,并添加@ServerEndpoint(URL),其中URL就是WebSocket服务端映射的URL 3. 重写onOpen、onClose、onMessage、onError等方法,并添加其同名注解。 4. 前端实现WebSocket
@ServerEndpoint("/webSocket/{token}")
public class WebSocketServer {
//保存WS客户端会话的集合
static Map<String, Session> sessionMap = new HashMap<>();
/**
* 当有客户端连接到webSocket服务端时触发的方法
*
* @param session 连接webSocket服务端的会话
*/
@OnOpen
public void onOpen(@PathParam("token") String token, Session session) {
String account = TokenUtils.verify(token);
if (account != null) {
System.out.println("有新客户端连接进来了,account是:" + account);
sessionMap.put(account, session);
}
}
/**
* 当客户向webSocket服务器发送消息时触发的方法
*
* @param message 就是客户端发送的信息
*/
@OnMessage
public void onMessage(@PathParam("token") String token, String message) throws IOException {
String account = TokenUtils.verify(token);
System.out.println("account为'" + account + "'客户端发来信息了,信息是:" + message);
if (message.equals("")) return;
for (String key : sessionMap.keySet()) {
if (!key.equals(account)) { //把自己排除掉,不给自己发信息
Session session = sessionMap.get(key);
if (session != null) {
session.getBasicRemote().sendText(message);
System.out.println("给ID为"+key+"发送信息了.");
}
}
}
// sessionMap.get(你要定向发信息的接收者ID).getBasicRemote().sendText("发送内容");
}
/**
* 当有客户端关闭/断开webSocket服务端连接时触发的方法
*
* @param session
*/
@OnClose
public void onClose(@PathParam("token") String token, Session session) {
String account = TokenUtils.verify(token);
System.out.println("account为'" + account + "'客户端断开连接了,ID是:" + session.getId());
sessionMap.remove(account);
}
/**
* 当有客户端与webSocket服务端连接发生异常/错误时触发的方法
*
* @param throwable
*/
@OnError
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学习Socket</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h1>学习Socket</h1>
<div>
<ul>
<li v-for="message in divMessages" v-text="message"></li>
</ul>
</div>
<input v-model="message"> <button @click="sendMessageToServer">发送</button>
</div>
<script>
//创建一个vue对象,该app对象包含了vue程序的所有属性和函数
const app = {
setup() {
let socket = null; //定义是个webSocket客户端对象
const message = Vue.ref(""); //要发送的信息
const divMessages = Vue.ref([]);
/**
* 连接webSocket服务端
*/
const connectToWebSocket = () => {
//创建一个webSocket客户端对象
/*
http => ws
https => wss
*/
socket = new WebSocket(location.protocol.replace("http","ws") + "//" + location.host + "/api/webSocket/" + localStorage.getItem("token"))
//为socket对象绑定事件
socket.onopen = ev => {
console.log("我连上服务器端了", ev);
//创建一个定时器,让socket定时循环向服务端发送信息,以保持连接状态
setInterval(() =>{
socket.send("");
}, 30000);
}
socket.onmessage = ev => {
console.log("服务器端发来消息了,消息是:", ev.data);
divMessages.value.push(ev.data);
}
socket.onclose = ev => {
console.log("断开服务器了,", ev);
}
socket.onerror = ev => {
console.log("连接服务端时发生了异常,", ev.reason);
}
}
/**
* 发送信息到服务端
*/
const sendMessageToServer = () => {
socket.send(message.value);
message.value = "";
}
//调用连接webSocket服务端方法
connectToWebSocket();
//要把需要渲染的变量和函数返回出去
return {
message,divMessages,
sendMessageToServer
}
}
}
//调用Vue的创建App方法,并挂载到id为“app”的DIV上面
Vue.createApp(app).mount("#app");
</script>
</body>
</html>
10. ContentType
application/json 消息主体是序列化后的 JSON 字符串,这个类型越来越多地被大家所使用 application/x-www-form-urlencoded 浏览器的原生form表单,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key和val都进行了URL转码 multipart/form-data 常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 form 的 enctype 等于这个值。 text/xml 是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范 text/html HTML格式 text/plain 纯文本格式 image/gif gif图片格式 image/jpeg jpg图片格式 image/png png图片格式
文件上传
@MultipartConfig
@WebServlet("/fileUpload")
public class FileUploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("开始上传...");
Part part = req.getPart("imgFile"); //根据参数获取上传文件部件
// String fileName = part.getSubmittedFileName(); //获取图片本身的文件名
String fileName = new Date().getTime() + ".jpg";
System.out.println("fileName:" + fileName);
//设置文件保存的路径
String uploadPath = getServletContext().getInitParameter("uploadPath");
File fileFolderPath = new File(uploadPath);
if (!fileFolderPath.exists()) fileFolderPath.mkdirs(); //如果上传路径不存在,则创建上传路径
System.out.println("uploadPath:" + uploadPath);
//上传图片到指定的路径
part.write(uploadPath + "/" + fileName);
JSONObject object = new JSONObject(true);
object.put("state", 200);
object.put("value", "/upload/" + fileName);
object.put("timestamp", LocalDateTime.now());
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write(object.toJSONString());
}
}
<div class="formSubmit">
<h4>完善个人信息</h4>
<label>
<div>生 日:</div>
<input type="date" placeholder="生日" v-model="birthday">
</label>
<label>
<div>电 话:</div>
<input type="text" placeholder="电话" v-model="telephone">
</label>
<label>
<div>头 像:</div>
<input type="file" v-model="imgFile" @change="changePath">
</label>
<button class="loginBtn" @click="submitInput">提交</button>
</div>
// 表单提交
const submitInput=()=>{
const formData=new FormData();
formData.append("imgFile",imgFile.value);
axios.post("/api/pictureUpload", formData, {
headers:{
Token: sessionStorage.getItem("token"),
birthday:birthday.value,
telephone:telephone.value,
id:user.value.id,
}
})
.then(response=>{
console.log(response.data);
user.value.headImage="../image/"+response.data.value;
}).catch(error=>{
console.log(error)
});
}