前言
本文是看黑马的视频做的总结,自己还查阅了一些资料,文章也加了自己的总结,这篇博客可以帮助大家入门,还有一些知识大家如果用到的话可以到时候再去学习一下,我写这篇主要是为了方便后面复习。希望能帮助到你!
我是李青水,一个大二学生
喜欢的朋友可以关注一下,下次更新不迷路!💕(●'◡'●)
目录
8.1.5 FilterConfig和FilterChain
一、Spring MVC简介
1.1Spring MVC是什么
Spring MVC是目前主流的实现MVC设计模式的框架。
1.2MVC是什么
-----MVC:是一种软件架构思想,把软件按照模型,视图,控制器来划分。
-----模型(Model):指工程中的JavaBean,用来处理数据
-----JavaBean分成两类:
一类称为实体类Bean:专门用来存储业务数据,比如Student,User
一类称为业务处理Bean:指Servlet或Dao对象,专门用来处理业务逻辑和数据访问
-----视图(View):指工程中的html,jsp等页面,作用是和用户进行交互,展示数据
-----控制层(Controler):指工程中的Servlet,作用是接收请求和响应浏览器
视图<--控制层-->模型
1.3MVC运行流程
- 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收
- Controller调用相应的Model层处理请求,处理完毕后结果返回到Controller
- Controller再根据请求处理的结果找到对应的View视图,渲染数据后最终响应给浏览器
Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层细节,并且开放出相关接口供开发者调用,让MVC开发更简单方便。
表现层(Controller),业务层(Service),持久层(Dao)
二、Spring MVC实现原理
2.1核心组件
DispatcherServlet:前置控制器,负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块
Handler:处理器,完成具体的业务逻辑,相当于Servlet
HandlerMapping:DispatcherServlet是通过 HandlerMapping把请求映射到不同的Handler
HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要进行一些拦截处理,可以通过实现该接口完成
HandlerExecutionChain:处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果有额外拦截处理,可以添加拦截器进行设置)
HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型转换、把表单数据封装到POJO等,这些一系列的操作都是由HandlerAdapter完成,DispatcherServlet通过HandlerAdapter执行不同的Handler
ModelAndView:封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet
ViewResolver:视图解析器,DispatcherServlet通过它把逻辑视图解析为物理视图,最终把渲染的结果响应给客户端
2.2Spring MVC工作流程
- 客户端请求被DispatcherServlet接收
- 根据HandlerMapping映射到Handler
- 生成Handler和HandlerInterceptor
- Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet
- DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理
- 返回一个ModelAndView对象给DispatcherServlet
- DispatcherServlet把获取的ModelAndView对象传给ViewResolver视图解析器,把逻辑视图解析成物理视图
- ViewResolver返回一个View进行视图渲染(把模型填充到视图中)
- DispatcherServlet把渲染后的视图响应给客户端
三、第一个Spring MVC项目
1、选择好Maven Archetype骨架
2、
3、
4、在web.xml中配置Spring MVC的DispatcherServlet
DispatcherServlet 是前端控制器,配置在web.xml文件中,Servlet依自已定义的具体规则拦截匹配的请求,分发到目标Controller来处理。
首先在项目中创建java和resources下的springmvc.xml
在resources目录中添加springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
在web.xml 配置Spring MVC的DispatcherServlet
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- springmvc配置文件加载路径
1)默认情况下,读取WEB-INF下面的文件
2)可以改为加载类路径下(resources目录),加上classpath:
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
DispatcherServlet对象创建时间问题
1)默认情况下,第一次访问该Servlet的创建对象,意味着在这个时间才去加载springMVC.xml
2)可以改变为在项目启动时候就创建该Servlet,提高用户访问体验。
<load-on-startup>1</load-on-startup>
数值越大,对象创建优先级越低! (数值越低,越先创建)
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<!--*.do拦截以do结尾的请求-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5、springmvc.xml进行配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
此文件用于定义Spring框架管理的对象(Bean)及其依赖关系、生命周期等配置信息。
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置自动扫描包 -->
<context:component-scan base-package="java"></context:component-scan>
<!-- 配置SpringMVC的视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
6、创建Controller控制器Handler,在里面编写接收参数,调用业务方法,返回视图页面等逻辑
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloHandler {
/**
*当客户端访问index请求时
* 自动关联到这个方法
* @return
*/
@RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
return "index";
}
}
7、配置Tomcat
8、测试
流程梳理
1、web.xml中DispatcherServlet接收到URL请求index,结合@RequestMapping(“/index”)注解把该请求交给index业务方法进行处理。
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2、执行index业务方法,控制台打印日志,并且返回"index"字符串。
@RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
return "index";
}
3、结合springmvc.xml中的视图解析器配置,找到目标资源:/index.jsp,即根目录下的index.jsp文件,把该JSP资源返回给客户端完成响应。
<!-- 配置SpringMVC的视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
index.jsp中
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
四、常用注解
4.1@RequestMapping常用参数
value:指定URL请求的实际地址,是@RequestMapping的默认值
method:指定请求的method类型,包括GET、POST、PUT、DELETE等
params:指定request请求中必须包含的参数值,如果不包含的话,就无法调用该方法
@RequestMapping(value = "/index",method = RequestMethod.POST,params="id")
五、参数绑定
5.1URL风格参数绑定
params是对URL请求参数进行限制,不满足条件的URL无法访问该方法,需要在业务方法中获取URL的参数值。
- 在业务方法定义时声明参数列表
- 给参数列表添加@RequestParam注解进行绑定
@Controller
@RequestMapping(value = "/index", method = RequestMethod.GET,params = {"id=1","name=tom"})
public class HelloHandler {
/**
*当客户端访问index请求时
* 自动关联到这个方法
* @return
*/
public String index(){
System.out.println("接收到了请求");
return "index";
}
}
5.2RESTful风格的URL参数获取
- 传统的URL:localhost:8080/hello/index?id=1&name=tom
- RESTful URL:localhost:8080/hello/index/1/tom
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){
System.out.println(num+"-"+name);
return "index";
}
5.3映射Cookie
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
5.4使用POJO绑定参数
POJO:简单的类对象(没有从任何类继承,没有实现任何接口)
1、编写POJO实体类
2、编写相关方法
3、写一个addUser.jsp页面
4、在web.xml中配置过滤器(为解决在ieda控制台中输出乱码)
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5、访问Tomcat服务器
结果
六、数据绑定
数据绑定:在后台业务方法中,直接获取前端HTTP请求中的参数
HTTP请求传输的参数都是String类型的,Handler业务方法中的参数是开发者指定的参数类型,比如int,Object,所以需要进行数据类型的转换
Spring MVC的HandlerAdapter组件会在执行Handler业务方法之前,完成参数的绑定,开发者直接使用即可
6.1基本数据类型
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){
return "id:"+id;
}
6.2包装类
@RequestMapping("/packageType")
@ResponseBody
public String packageType(Integer id){
return "id:"+id;
}
6.3数组类型
@RequestMapping("/arrayType")
@ResponseBody
public String arrayType(String[] names){
StringBuffer buffer = new StringBuffer();
for (String str:names){
buffer.append(str).append(" ");
}
return "names:"+buffer.toString();
}
6.4POJO、List、JSON等
七、文件的上传下载
7.1单文件上传
1.底层使用的是Apache fileupload 组件完成上传功能,Spring MVC只是对其进行了封装,简化开发
pop.xml中
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
springmvc.xml中(为了把二进制数据解析成对象)
<!-- 文件的上传-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
这段配置代码告诉 Spring 容器创建一个 CommonsMultipartResolver Bean,它作为 Spring MVC 中的 MultipartResolver 实现,负责解析含有文件上传的 HTTP 请求,并将其转换为 Spring 可以处理的格式(如 MultipartFile 对象),从而使得应用程序能够方便地接收和处理用户上传的文件。在实际使用时,Spring MVC 会自动查找名为 "multipartResolver" 的 Bean 来处理 multipart 请求,无需在 Controller 中显式调用。
2、JSP页面
需要访问静态资源
jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="img"/>
<input type="submit" value="提交">
<!-- 加上/代表从根目录也就是8080开始找 -->
</form>
<img src="${src}"/>
</body>
</html>
3、拦截后执行的方法
@Component
@RequestMapping("/file")
public class FileHandler {
/**
* 文件是以二进制流传输的
* @param img
* @return
*/
@PostMapping("/upload")
public String upload(@RequestParam("img") MultipartFile img, HttpServletRequest request){
if (img.getSize()>0){
String path = request.getSession().getServletContext().getRealPath("file");
String filename = img.getOriginalFilename();
File descFile=new File(path, filename);
try {
img.transferTo(descFile);
request.setAttribute("src", "/file/"+filename);
} catch (IOException e) {
e.printStackTrace();
}
}
return "upload";
}
}
4、实现
提交后网页会回显出图片
7.2多文件上传
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>多文件上传</title>
</head>
<body>
<form action="/file/uploads" method="post" enctype="multipart/form-data">
file1:<input type="file" name="imgs"/><br>
file2:<input type="file" name="imgs"/><br>
file3:<input type="file" name="imgs"/><br>
<input type="submit" value="提交"/>
</form>
<c:forEach items="${pathList}" var="path">
<img src="${path}" width="300px">
</c:forEach>
拦截方法
@PostMapping("/uploads")
public String uploads(@RequestParam("imgs") MultipartFile[] imgs,HttpServletRequest request){
List<String> pathList=new ArrayList<>();
for (MultipartFile img:imgs){
if (img.getSize()>0){
String path = request.getSession().getServletContext().getRealPath("file");
String filename = img.getOriginalFilename();
File descFile=new File(path, filename);
try {
img.transferTo(descFile);
pathList.add("/file/"+filename);
} catch (IOException e) {
e.printStackTrace();
}
}
}
request.setAttribute("pathList", pathList);
return "uploads";
}
实现
7.3文件下载
JSP页面通过超链接点击进行下载
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件下载</title>
</head>
<body>
<a href="/file/download?fileName=皮卡丘.jpg">皮卡丘.jpg</a>
<a href="/file/download?fileName=柯南.png">柯南.png</a>
<a href="/file/download?fileName=springmvc.png">springmvc.png</a>
</body>
</html>
拦截方法
TODO:
/**
* 根据文件的名字进行下载
*/
@GetMapping("/download")
public void download(String fileName,
HttpServletRequest request,
HttpServletResponse response) {
if (fileName!=null){
String path = request.getSession().getServletContext().getRealPath("file");
File file=new File(path,fileName);
OutputStream out=null;
if (file.exists()){
//设置下载文件
response.setContentType("applicationContext/force-download");
//设置文件名
response.setHeader("Context-Disposition", "attachment;filename="+fileName);
try {
out=response.getOutputStream();
out.write(FileUtils.readFileToByteArray(file));
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
实现
八、过滤器、监听器
8.1过滤器(Filter)
8.1.1定义
定义:过滤器是用来过滤请求和响应的Java接口。
8.1.2原理
原理:
当我们使用过滤器时,过滤器会对游览器的请求进行过滤,过滤器可以动态的分为3个部分,1.放行之前的代码,2.放行,3.放行后的代码,这3个部分分别会发挥不同作用。
第一部分代码会对游览器请求进行第一次过滤,然后继续执行
第二部分代码就是将游览器请求放行,如果还有过滤器,那么就继续交给下一个过滤器
第三部分代码就是对返回的Web资源再次进行过滤处理
我们使用过滤器,也就是说,不止请求会经过过滤器,我们的响应也会经过过滤器。
8.1.3 过滤器接口定义
doFilter方法参数:
-----ServletRequest:这是客户端请求的包装对象。这个对象提供了读取请求参数、请求头、Cookies等方法。
-----ServletResponse:这是服务器响应的包装对象。这个对象提供了设置响应状态码、响应头、发送响应数据等方法。
-----FilterChain:这是一个过滤器链的表示,它包含了当前过滤器之后的过滤器以及目标Servlet或Controller。在
doFilter
方法中,必须调用FilterChain
对象的doFilter
方法,以便将请求传递给链中的下一个过滤器,或者如果已经是最后一个过滤器,则传递给目标Servlet或Controller。
创建:
-----第一步:Filter就在servlet-api.jar中,我们将该jar包放到WEB-INF下的lib目录下面。
-----第二步:继承并实现其接口。
public class MyFilter implements javax.servlet.Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 在将请求传递给链中的下一个元素之前执行一些预处理
// 例如,记录请求信息
System.out.println("Filtering request path: " + req.getRequestURI());
// 继续执行过滤器链,如果这是最后一个过滤器,则请求将到达目标Servlet或Controller
chain.doFilter(request, response);
// 在请求被处理之后执行一些后处理
// 例如,记录响应信息
System.out.println("Filtering response status: " + res.getStatus());
}
}
8.1.4配置过滤器拦截路径
配置Filter的拦截路径有2种方式,一种是注解,一种是xml方式,本文只对注解进行讲解。
使用@WebFilter
里面的配置项还是有很多的,下面我对常用配置项进行说明:
filterName:该filter的名字
initParams:初始化参数
displayName:filter显示名称
servletNames:指定对哪些servlet进行过滤
asyncSupported:是否支持异步模式
urlPatterns:指定拦截路径
value:指定拦截路径
注意:urlPatterns和value是一样的。urlPatterns和value只能配置一个,不能两个都配置,两个都配置就会报错。
说明:如果我们仅仅需要配置一个拦截路径,那么我们可以直接简写@WebLister("拦截路径"),如@WebFilter("/*")就是拦截所有请求。
@WebFilter(value = {"/*"},filterName = "MyFilter")
public class MyFilter implements javax.servlet.Filter{
8.1.5 FilterConfig和FilterChain
FilterConfig和FilterConfig这2个对象是由服务器(Tomcat)在创建和调用Filter对象时所传入的,这2个对象十分有用,FilterConfig对象可以读取我们配置的初始参数,FilterChain可以实现多个Filter之间的连接。
FilterConfig
老规矩,我们要学习一个对象,首先查看类图和源代码
- getFilterName():获取filter的名称
- getServletContext():获取ServletContext
- getInitparamter(String var1):获取配置的初始参数的值
- getInitParamterNames():获取配置的所有参数名称
接下来在init方法中使用FilterConfig来读取配置的数据库的信息,然后输出。
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class MyFilterConfig implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("-----------获取全部key:value------------");
//得到所有配置参数的名字
Enumeration<String> names = filterConfig.getInitParameterNames();
while (names.hasMoreElements()) {
//得到每一个名字
String name = names.nextElement();
System.out.println(name+" = "+filterConfig.getInitParameter(name));
}
System.out.println("-----------end.....------------");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
FilterChain
可以发现FilterChain就只有一个方法,其实这个方法就是用来对拦截进行放行的,如果有多个拦截器,那么就会继续调用下一个Filter进行拦截。doFilter方法需要传入个参数,一个是ServletRequest,一个是ServletResponse参数,这个直接传入进行。
Tomcat在调用过滤器时,默认就会传入Request和Response,这个参数封装了请求和响应,我们直接使用就行。ServletResquest和ServletResponse可以直接强转成HttpServletRequest和HttpServletResponse,然后使用相应的方法。
将ServletRequest转成HttpServletRequest
FilterChain应用实例
我们前面一直都是一个Filter,现在我们来配置2个Filter,通过FilterChain来进行多个过滤。
第一个过滤器
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("调用过滤器01对请求进行过滤~~~~");
//放行,如果还有过滤器,那么就执行下一个过滤器
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("调用过滤器01对响应进行过滤~~~~");
}
@Override
public void destroy() {
}
}
第二个过滤器
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class Filter02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("调用过滤器02对请求进行过滤~~~~");
//放行,如果还有过滤器,那么就执行下一个过滤器
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("调用过滤器02对响应进行过滤~~~~");
}
@Override
public void destroy() {
}
}
输出
执行顺序图
多个Filter的执行顺序
如果我们是在web.xml中配置的过滤器,那么过滤器的执行顺序就是<filter-mapping>在web配置的顺序,配置在上面那么就会先执行。
如果我们是使用@WebFilter进行配置的,那么执行顺序就是字符比较顺序来执行,例如有2个过滤器,一个是AFilter,一个是BFilter,那么AFilter就会先执行。
如果注解和xml混用,那么在web.xml中配置的会先执行。
8.2监听器(Listener)
8.2.1定义
定义:Listener就是接口,用来监听某种事物的变化,然后通过回调函数,反馈给客户或者程序。
8.2.2原理
当Web容器检测到定义的事件发生时,它会自动调用相应监听器的回调方法。例如,当一个session被创建时,Web容器会调用所有实现了
HttpSessionListener
接口的监听器的sessionCreated
方法。
8.2.3监听器的类型
在Servlet规范中,定义了多种类型的监听器,它们分别监听不同类型的事件:
- ServletRequest监听器:监听ServletRequest对象的创建和销毁。
- ServletResponse监听器:监听ServletResponse对象的创建和销毁。
- Session监听器:监听HttpSession对象的创建和销毁,以及session属性的变化。
- ServletContext监听器:监听ServletContext对象的创建和销毁,以及context属性的变化。
- Servlet监听器:监听Servlet的生命周期事件。
8.2.4监听器的实现
要实现一个监听器,你需要创建一个实现了特定监听器接口的Java类。例如,如果你想要创建一个Session监听器,你的类需要实现HttpSessionListener
接口。
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionEvent;
public class MySessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// Session创建时执行的操作
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// Session销毁时执行的操作
}
}
8.2.5监听器的配置
想要实现监听器还需要对其进行配置
监听器可以在web.xml中配置,也可以通过注解配置。在web.xml中,你可以这样配置一个监听器:
<listener>
<listener-class>com.example.MySessionListener</listener-class>
</listener>
8.2.6监听器如何触发
当Web容器检测到定义的事件发生时,它会自动调用相应监听器的回调方法。例如,当一个session被创建时,Web容器会调用所有实现了HttpSessionListener
接口的监听器的sessionCreated
方法。