知识如果学了没有记下来,如果没有真的完全的理解,就等于没学过!!!
直接解压到本地
直接删除文件夹
双击:bin\startup.bat
修改 conf/logging.propertis
检查JAVA_HOME 环境变量,一般就是这个问题
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port><!--访问端口号-->
<path>/</path><!--项目访问路径-->
</configuration>
</plugin>
</plugins>
</build>
要先安装 .Mavne Helper 这个插件
选中项目,右键,tomcat run
注意需要配置虚拟路径不能用tomcat插件
1.将本地Tomcat集成到Idea中,进行项目部署
步骤
选择本地tomcat目录
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
request.setCharacterEncoding("utf-8")
记得一定要把这个写在最上面
get模式,tomcat8之后不需要更改
servlet在tomcat中是 单例 线程不安全的
-单例:所有请求都是同一个实例去响应
-线程不安全:一个线程需要根据这个实例中的某个成员变量去做逻辑判断,但是在中间某个实际,另一个线程改变了这个值,比如通过一个值去做if 或 else 判断,就会导致第一个线程执行路径发生变化
-解决办法:尽量的不要再servlet中定义成员变量,如果不得不定义成员变量,那么
1、不要去修改成员变量的值
2、不要去根据成员变量去做逻辑判断
1、先实例化,调用构造方法
2、init() 初始化 service() 执行服务 destroy() 销毁
继承关系
javax.servlet.Servlet接口:
void init(config) - 初始化方法
void service(request,response) - 服务方法
void destory() - 销毁方法
javax.servlet.GenericServlet抽象类:
void service(request,response) - 仍然是抽象的
javax.servlet.http.HttpServlet 抽象子类:
void service(request,response) - 不是抽象的
1、请求行
请求的方式 2、请求的URL3、请求的协议(一般是HTTP1.1)
2、请求头
很多客服端要告诉服务端的信息,我的浏览器型号、版本、我能接收的内容的类型、我给你发的内容的类型、内容的长度等等
3、请求体
get方式,没有请求体,但是有一个queryString
post方式,有请求体,form data
json格式,有请求体,request payload
(这三个我都不懂)
打开谷歌浏览器,先打开F12
输入servlet地址
因为是第一次访问,服务器会塞给浏览器一个servlet地址,用的是response
第二次访问
因为浏览器已经有session了,所以去请求服务器时候,会通过 request 将session 携带过去
用这个sessionId来区分不同客户端,称作会话跟踪技术
这个sessionId是全球唯一码
只在当前浏览器的访问中,一台电脑的其他浏览器都不行
一次连接
网页关闭之前,一直有效,如果30分钟之内没有使用,也会失效,可以手动设置时间
甚至可以,直接关闭
叫servlet上下文
tomcat停止,这个上下文就结束了
可以手动移除属性
ServletContext.application=request.getServletContext()
application.setAttributr(k,v)
ServletContext.application=request.getServletContext()
application.getAttributr(k)
org.slf4j
slf4j-api
1.7.7
ch.qos.logback
logback-core
1.1.7
ch.qos.logback
logback-access
1.1.7
ch.qos.logback
logback-classic
1.1.7
彩色日志 logback.xml
${APP_NAME}
${CONSOLE_LOG_PATTERN}
${LOG_DIR}/logFile.log
true
${FILE_LOG_PATTERN}
${LOG_DIR}/dayLogFile.%d{yyyy-MM-dd}.log
30
${FILE_LOG_PATTERN}
mysql
mysql-connector-java
5.1.47
mybatis
org.mybatis
mybatis
3.5.7
junit @Test依赖
junit
junit
4.12
test
如果mapper接口名称和sql映射文件名称相同,并在同一目录下,则可以使用包扫描方式简化sql映射文件的加载
这个是写在mybatis-config.xml
起了别名,就可以直接写类名,而且不区分大小写
这个是写在mybatis-config.xml
public class MyBatisUtils{
private static SqlSessionFactory sqlSessionFactory=null;
//初始化SqlSessionFactory对象
static{
try{
//使用MyBatis提供的Resources类加载MyBatis的配置文件
Reader reader= Resources.getResourceAsReader("mybatis-config.xml");
//构建SqlSessionFactory工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
}catch (Exception e){
e.printStackTrace();
}
}
//获取SqlSessionFactory 对象的静态方法
public static SqlSessionFactory getSession(){
return sqlSessionFactory;
}
}
<resultMap id="fruitReturnMap" type="Fruit">
<result property="fId" column="f_id">result>
<result property="fName" column="f_name">result>
<result property="fPrice" column="f_price">result>
<result property="fCount" column="f_count">result>
<result property="fRemark" column="f_remark">result>
resultMap>
在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。
当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动帮你找到对应要执行的SQL语句
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
在页面html 这个标签里面加这行语句
在web.xml配置文件里添加参数
view-prefix
/
view-suffix
.html
使用例子
名称
单价
库存
购买地址
操作
列表数据为空
苹果
5
100
拼多多
新建ViewBaseServlet(有两个方法) , 配置两个 : view-prefix , view-suffix
${#lists.isEmpty(fruitList)}
${#lists.isEmpty(session.fruitList)}
${#lists.isEmpty(application.fruitList)}
记录一下,之前跟着黑马也做了增删改查,而且是用VUE和AXIOS做的,所以这里这是看一下用普通方法(thymeleaf)怎么做
先设置一个根路径
其中day01是虚拟路径
这样设置之后,再写其他路径,比如 导入js文件就可以直接写比如这样
但是要注意,这个是TOMCAT的地址,在软件里面地址可能是这样的
http://localhost:63342/epidemic01/src/main/webapp/index.html?_ijt=ogf5d4qajludu3bqrucdnjinpg&_ij_reload=RELOAD_ON_SAVE
所以要把服务器跑起来测试
*{
color: threeddarkshadow;
}
我还以为是多高大上的代码呢,原来就是个设置颜色
比如div 或者 body 就是更改所有这个属性的属性
解决方案:1、更改某个字,当字变了,那也更新过去了
2、不启动服务器,大概写好了,再去弄
body{
margin:0;
padding:0;
background-color:#808080;
}
#div_container{
width:80%;
height:100%;
border:0px solid blue;
margin-left:10%;
float:left;
background-color: honeydew;
border-radius:8px;
}
用这个方式,可以让上面的div居中
width: 80%;
margin-left: 10%;
height: 100%;
border-radius: 数值px;
设置椭圆边框
text-align:center;
让文字居中不要设置什么内外边框,直接上这个
而且,注意
width: 80%;
text-align: center;
宽度80的时候也不能居中
6、表格边框要这么写
#table_fruit ,#table_fruit tr, #table_fruit th, #table_fruit td{
border: 2px black solid;
}
看好了,表格边框是这样的,不是说你这样就可以了
#table_fruit{
border: 2px black;
}
这个是错的,第一不是单写个表格就行了,还要写后面的tr th td
第二 border 要写上 solid 这个东西
位置信息不能在写在上面
#table_fruit ,#table_fruit tr, #table_fruit th, #table_fruit td{
这种东西里面,不然会变得不幸
border-collapse: collapse;
合并线要写在上面那一坨里面,而不是表格里面
line-height: 26px;
设置行高,写在表格属性里面
font-weight:lighter;
文字粗细演示
font-family: "黑体";
设置字体
7、表格边粗细不一
调整浏览器缩放比例
8、添加图片
9、合并单元格
列表数据为空
写在html页面里,不是css
10、选中某一种类型
input[type=text]{
width: 70%;
}
2、编辑和修改特定库存信息
1、渲染覆盖
苹果
你看这行代码,你在静态访问的时候没有问题,在动态访问的时候也没有问题。
但是一旦通过访问servlet的方法
@WebServlet("/fruit")
public class FruitServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
FruitService fruitService=new FruitServiceImpl();
List fruitsList = fruitService.selectAll();
HttpSession session = req.getSession();
session.setAttribute("fruitList",fruitsList);
super.processTemplate("index",req,resp);
}
}
就出了问题,是因为被前面的thymeleaf 的渲染给覆盖了,这种东西,要是我自己写,一定会发疯的,一遍一遍的去调试,而不知道错误在哪里,我真的,之前一直因为这种事情心态爆炸。
网页跳转那里也是,所以下回遇到bug千万别急眼,一定是自己的基础知识出了问题,找原因就好,加油!!
2、路径问题
苹果
老师的意思是现在我的index主页位置直接在wepapp下面,如果之后路径很深的话,这样写不太好,要加上根目录,我先在不太懂,等之后碰壁了应该就懂了,要写成下面这样
苹果
没太懂,但是写成这样比较好
3、height设置不生效问题
%是一个相对父元素计算得来的高度,要想使他有效,我们需要设置父元素的height;
要特别注意的一点是,在之中的元素的父元素并不仅仅只是,还包括了。
所以我们要同时设置这两者的height,只设置其中一个是不行的:
html ,body{
height: 100%;
}
4、取消body边距无效
原因:我的
的边距有问题,我不知道为什么 之前的网页没有这个问题
5、get 可以发送序号过去 ?id=1
苹果
这行代码对应的servlet需要一个id去查询对应的数据,把数据渲染到编辑页面上,原来是通过get方式传递的
6、thymeleaf 拼接属性变换
th:href="@{'/edit.do?fId='+${fruit.fId}}">
th:href="@{/edit.dofId(fId=${fruit.fId})}
7、非空判断最好写在一个工具类里面
1、String 判断非空
8、编辑页面里的一些问题
1、我没写name,这个很重要,我编辑好了,要修改的,所以要有name去提交
2、我不知道thymeleaf那个绑定变量怎么写
不遍历的话直接写
遍历这样写
苹果
5
100
拼多多
1、原来是直接写的
因为我用req,把数据发送过去了,而且没有遍历,所以可以直接写
th:value="${fruit.fCount}"
2、也可以这样写
th:object="${fruit}";
th:value="*{fname}";
9、servlet映射无效
原来是我
@WebServlet("update.do")
//没写/
@WebServlet("/update.do")
10、bigDecimal 和 String 转换
BigDecimal bigDecimal = new BigDecimal(s);
11、我吐了,真的,那个session 提交和关闭别忘了好不好
12、更新数据后,网页数据没有变
原因是我把数据存到了session里面,然后遍历渲染到网页上。
更新完了数据,但没有把更新后的数据 重新保存到 session 上
但是上面的做法是冗余的
做法是 重定向到主页,(就是给indexServlet发请求)主页会自己获取,就好了
3、添加和删除数据
1、display: inline-block; 无效
因为没有设置宽高
2、display: inline-block; 无效
因为前面的网页我是直接去请求静态资源,导致添加的网页没有经过thymeleaf的渲染,语法不生效
3、取消超链接下划线
text-decoration=none
4、删除
th:onclick="'deleteByid('+${fruit.fId}+')'"
正常的字符串拼接,注意外面是双引号,里面是单引号
简易写法
th:onclick="|deleteByid(${fruit.fId})|"
5、引入js
6、删除delete语句
delete from fruit where f_id=x;
7、忘了写@WebServlet(“/delete”)
请求的资源[/day01/delete]不可用
4、分页查询
我先自己写
我知道怎么把数据传到前端
但是前端怎么写啊
我先写个写死页数的分页查询吧
后端分页需要的数据写完了
前端是这么写的
(page-1)*5
== 记住他是基于当前页码的上一页,下一页进行查询的
1、写了分页查询没有指定返回集
2、调整摁钮大小
.big{
width: 80px;
height: 30px;
font-size: 16px;
font-weight: bold;
}
给所有摁钮加上class,然后调整width hright
3、调整字体粗细
font-weight: bold;
4、我要传一个page页码过去,而不是总数
5、计算页数的公式
int lastPage=(pageCount+5-1)/5;
6、判断是否是摁钮不可用
@Test
public void ifTrue(){
System.out.println(1==1);
}
这个结果是true
同理
5、根据关键字查询
说实话上个分页条前端我没写出来,是因为不知道语法,这个我应该能写出来
先写后端,然后测试
再写前端
1、模糊查询
@Select("select * from fruit where f_name like '%${keyWords}%';")
用这种方式写,有被注入攻击的风险
2、提交查询关键字
我是用dom做的,老师使用表单提交做的
3、查询库存总记录数也要考虑keyWord
总体思想
1、隐藏域发送 opea=search
2、判断是怎么过来的
3、如果是搜索进来的,那么 开始页数为一 把keyWord 存到session里面
如果不是keyword要从session中获取
4、走下面需要从session中获取关键字,req里面的session没了
6、总结
1、记得更新session里面的数据
七、MVC各个层的设计
连接进来
Character Encoding Filter
用来把tomcat post方法默认的 iso8859-1 转换为 UTF-8编码
Open Session InView Filter
用来进行事务管理,把DAO层和Service层里面所有的try catch 都变为运行时异常,在这里捕捉,统一进行commit 或 rollback
1、开启事务
try{
2、放行
3、提交
}catch(){
4、回滚
}
ThreadLocal(难点)
这个是本地线程方法,就类似于流水线上面的工具箱,一个工具箱,三个人用,一个连接,三个方法用,保证连接是一个
为什么要保证连接是一个来着?
:如果连接三个方法用一个连接,回滚能回滚三个
DispatcherServlet 这里没懂的比较多,需要多敲代码
就是黑马那个解析链接 找到controller
根据传过来的参数 找到对应的service方法
难点
1、参数处理
2、invoke(这个不难)
3、视图处理(这个是啥?)
IOC Container
IOC容器 控制翻转 依赖注入
用标签来指定依赖
伪代码
一、servlet优化1
1、总体思想
总体思想是,判断传过来的operate这个值的属性,来判断执行哪个方法
1、把 发送的地方改成 总的那个地方,2、然后用发送两个参数的方法,再传一个
注意要写成单引号
2、function方法怎么改
3、还可以隐藏的发过去
为什么是三种方法呢,第一种和第三种的区别是啥
第一种通过连接发值可以发两个
要是提交表单的方式,就只能隐藏域发送了
4、之前的重定向,要统一改成现在的总servlet,会通过初始值 指定到主页
5、如果这里面的值都没有就说明是被手动输入了,抛出个错误
6、浏览器? &
window.location.href='fruit?fId='+fId+'?operate=delete';
window.location.href='fruit?fId='+fId+'&operate=delete';
7、我以为闹鬼了,点击编辑功能,他直接把数据删了,原来是把数据变成空了,然后不显示
原因二是 ,他是要通过edit这个跳转到edit.html这个页面,我把这步省了
还行吧,20分钟的东西,磨了一个小时
servlet优化2 dispatcherServlet引入
1、通过方法名 用反射实现
2、默认的index
我真他妈草了,一直在怎么得不到参数,让他去找index,直接在上面设置值就可以了
3、反射的对象获取
4、对象才有getClass方法,this也是对象
二、servlet优化2.1 dispatcherServlet引入
步骤
1、在dispatcherServlet 的构造方法里面解析那个配置文件
2、创建一个DocumentBuilderFactory
3、创建DocumentBuild对象
4、创建Document对象 一定要导==org.w3c.com ==这个包的
1、setAccessible 访问private 需要这个属性
设置访问性,反射类的方法,设置为true就可以访问private修饰的东西,否则无法访问
2、中央控制器的概念
1、实现步骤
1、新建servlet,拦截*.do为结尾的请求
2、得到字符串对应控制器
3、把之前的servlet变成普通的类
4、在一个文件当中,对这两者的关系做一个说明
1、xml声明的固定写法
?>
java操作节点的一些文档
这个是java操作节点的一些文档
2、反射调用方法 变量居然是method
for (Method fruitMethod : fruitMethods)
我自己写了反射,跑一下试试,哈哈哈哈哈
3、反射调用方法 记得用这个getDeclaredMethod
而且 忘了写 参数类型.class
4、这么搞他的搜索功能是坏的,我不知道他后面是怎么解决的,之后再说吧
private void search(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
index(req,resp);
}
2、我应该先敲一遍代码,然后看看老师那里翻了错误,我也跟着改
1、根据请求的url获取servletPath,解析出一个名字
2、解析加载配置文件,读取bean 扔到配置文件里面 (这是我几天前写的,我现在就看不懂了)
3、调用controller里面的方法
3、卧槽,困扰我那么久的问题终于要解决了
就是因为我把原来的servlet给改成普通类了,他就不会去调用它的Init方法,那个方法里面有个servletContext参数,没有,我现在来写一遍
1、因为FruitController 不是一个servlet方法了,所以不会去调用init方法
之前FruitServlet是一个servlet组件,那么其中的Init方法一定会被调用
之前的init方法会出现一句话,super.init
有了这句话就会对用 viewBaseServlet 里面的init 方法
现在它已经不是servlet方法了,所以不会去调用init方法,也就不会去调用viewBaseServlet 里面的init 方法
2、不能自动调用,那我就自己调用
3、不写构造里了,写在Init里
ServletContext就是最大的那个作用域
4、因为我要把那个参数传进去
扔到这里面
5、还是没用的原因
6、这么改
这里也改一下就好了
三、servlet优化3 提取视图资源处理通用代码 与 统一获取参数
1、重定向和转发也可以提取出来
1、解决转发冗余
把这个String发送给中央控制器,让中央控制器帮我们进行统一的转发
核心代码
try {
Method declaredMethod = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
if(declaredMethod!=null){
declaredMethod.setAccessible(true);
Object invoke = declaredMethod.invoke(controllerBeanObj, req, resp);
//在这里执行了方法,然后统一去跳转
if(invoke!=null){
String redirectStr=(String)invoke;
if(redirectStr.startsWith("redirect")){
//如果包含这个,那么跳转
String substring1 = redirectStr.substring("redirect:".length());
resp.sendRedirect(substring1);
}else {
super.processTemplate(redirectStr,req,resp);
}
}
}else{
throw new RuntimeException("没有这个方法");
}
2、search 无效 我有点NB了
2、解决那个需要view的
2、每一个方法都有req.getParameter这个方法,代码冗余
1、解决那个需要view的
直接把形参写上去,把需要req.getParameter都删掉,
2、统一抽取到父类里面 就是DispatcherServlet里面
三步走
3、思考过程
每个方法需要获取的参数的都一样,我要获取那些参数,是根据这个方法的参数签名来获取的
参数签名
方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。
注意,方法签名不包括方法的返回类型。不包括返回值和访问修饰符。
public double calculateAnswer(double wingSpan, int numberOfEngines,
double length, double grossTons) {
//do the calculation here
}
上面方法的签名是:
calculateAnswer(double, int, double, double)
1、获取当前方法的参数,返回参数数组
Parameter[] parameters=method.getParameters();
2、这里有个错误,因为之前把方法参数改了,不是每个方法都有req,resp的
3、解决方法是获取所有方法,然后循环
如果能获取到方法名,就可以直接req.getParameter了
4、从JDK8 开始可以获取反射的名称
这个表示在编译的时候,形参自带参数名称
.class文件会稍微大一点
记得把编译好的文件删一下,重新编译
5、把参数存到数组里面
如果是复选框的话,用这个方法,但是不考虑那么复杂
这三个参数是不需要req.getParameter的
最终写法
6、直接把实参数组传到反射里面了,这能行吗
7、程序逻辑bug
8、点下一页的时候报了这个错误
错误原因是,访问主页的时候
这张图片里的page是null 然后默认给了1 ,但是一旦,点了下一页
这里就要值了,但是page这个值应该是integer 我往数组里放的是String
java.lang.Integer
9、这样这个controller里面只需要考虑怎么进行业务的操作,怎么获取参数,怎么跳转都不用考虑了
4、我自己写的时候遇到的问题
1、语言等级
idea还有语言等级,有些方法貌似level 8 才能用,比如这个
Parameter[] parameters = m.getParameters();
2、我不知道怎么找参数的名字
我超,原来打了断点还可以下一步
3、我改了可以获取到参数名字,但是无效
我他吗吐了,我忘了删除已经编译好的文件
4、草拟吗啊,我为什么 -parameters这个不好使,在maven上配置也不好使
maven-compiler-plugin
3.8.0
1.8
utf8
-parameters
用了这个好使了,可能可maven compiler-plugin 的版本有关
5、如果以后还有问题,来看看这个文章
maven-jdk问题
6、索引越界,越来是j和i写错了。。。
for (int j = 0; j < parameters.length; j++) {
//这里把每个参数都取出来了
Parameter parameter = parameters[i];
7、声明数组放循环里了,结果导致空指针
8、那个变量数组还没循环存完呢,我就去反射方法了
9、报空指针,添加了非空判断,但是好像没有解决
if(typeName.equals("java.lang.Integer")){
//integer可以存null
if(!parameter1.equals("null")){
paraObj = Integer.valueOf(parameter1);}
}
if(typeName.equals("java.lang.Integer")){
//integer可以存null
if(!(parameter1 ==null)){
paraObj = Integer.valueOf(parameter1);}
}
改成这种格式
10、报类型转换异常
if(typeName.equals("java.math.BigDecimal")){
if(!(parameter1 ==null)){
paraObj = new BigDecimal(parameter1);}
}
paraObj=parameter1;
你看看你写的这个顺序,能不空指针吗
11、为什么invoke 能传进去个object数组,因为 下面这个,想想那些List=Arrlist之类的
public void object1(){
int a=0;
Object b=a;
System.out.println(b instanceof Integer);
}
5、我把本地项目删了,从git上拉取了一下,出现了错误
java: JDK isn't specified for module 'javaWeb'
解决方法
添加链接描述
vcs 复制码云上面的仓库地址
Git
6、弄了一上午git出错,怎么都不能删除当前分支,但是不知道怎么弄的突然好了,用了下面这个链接以及这个链接的方法
git
添加链接描述
添加链接描述
四、servlet4 api
1、servlet-api
如果我们想在servlet初始化时做一些准备工作,我们可以
重写那个Init()空实现方法
init 方法只会执行一次
2、配置文件配置方法
3、注解配置方法
4、获取配置参数方法
5、405报错
因为没有重写servlet里的service方法,所以当网页会报错405,因为我们应该是执行get方法,进来的,doget方法里面会报405
6、配置上下文参数
这样可以获取 这是在Init 里面写的
在服务方法中也可以通过req获取
7、读取方法
五、业务层
- 什么是业务层
1) Model1和Model2
MVC : Model(模型)、View(视图)、Controller(控制器)
视图层:用于做数据展示以及和用户交互的一个界面
控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件
1) pojo/vo : 值对象
2) DAO : 数据访问对象
3) BO : 业务对象
- 区分业务对象和数据访问对象:
1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…
2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
注册:
1. 检查用户名是否已经被注册 - DAO中的select操作
2. 向用户表新增一条新用户记录 - DAO中的insert操作
3. 向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作
4. 向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作
5. 向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作
6. …
3) 在库存系统中添加业务层组件
六、IOC
他想做到service删掉 controller 不报错
dao层删掉 service层 不报错
???
啊,就是那个不爆红
private FruitService=null
一、核心思想
1、添加配置文件里
在当前的配置文件里面配置三个bean
这三个bean其实就是对应的单个组件
计划在下一次启动中,他就会把这三个组件准备好,并且放在一个容器里面
谁想要的时候我就主动给谁
2、建立接口
3、建立实现类
实现 输入id获得对象的方法
建立一个容器
4、把之前 dispatcherServlet里面的那个方法提取出来
并把dispathcerServlet里面的错误解决掉
dispatcherServlet里面的这个方法报错
解决方法
调用这个接口里面的方法
但是这样做的问题是 我虽然的到了对象,但是那个对象指向的是Null,我需要把实现类注入进去
5、层与层之间的依赖,在配置文件里写
这个name就是我 水果服务实现类 里面需要的那个属性名字 就是=null 的那个
最终效果,需要哪个bean 和 bean之间的关系
6、组装bean之间的依赖关系
再看一遍这个这个是java操作节点的一些文档
切记,在中央控制器的init 方法里面一定要 beanFactory初始化了
7、我NB了,之前觉得最难得一节课我也看懂了
IOC 依赖翻转
DI 依赖注入
8、好了,我要实现IOC了,开干
1、第一步是把bean 写到配置文件里面
pro什么那个我不会写
property
name 和 ref 不是 name 和 value
<beans>
<bean id="fruit" class="com.kerwin.controller.fruitController">
<property name="fruitService" ref="fruitService"/>
bean>
<bean id="fruitService" class="com.kerwin.service.impl.FruitServiceImpl">
<property name="fruitDao" ref="fruitDao"/>
bean>
<bean id="fruitDao" class="com.kerwin.dao.FruitDao"/>
beans>
配置文件应该是这样吧,我自己写的
2、BeanFactory
我哭了,我的service 里面 用的是SqlSessionFactory session 方法,没有耦合
卧榻嘛杀了,我居然没加括号??这是我写的????
3、依赖注入代码要写在哪个位置
卧槽我写完了,运行一下吧。
4、我虽然写完了,但肯定会出错,改完了,我就出去骑自行车
1、.InstantiationException 实例化异常
我的fruitDao 是一个接口,不能实例化
2、beanObj 可能找错了
要找那个有子节点,并且子节点名字为property 的类
七、总结
我把serviceimpl写在方法内,作用域小,写在成员变量位置,扩大作用域,线程会不安全
1、控制翻转
无论你把这个实例,写在方法体或者成员变量里,方法体内会频繁的创建销毁,成员变量就会好一些
虽然JAVA虚拟机 有自动垃圾回收机制
但是总的来说,实例的声明周期,是由程序员维护的
但是之后我们把这些实例通过配置文件和BeanFactory 放在了一个容器里面
这个容器创建,那么实例就创建
容器销毁,实例就销毁了
那么这些实例的声明周期就不在程序员的手上了
转移到BeanFactory 里了,这个BeanFactory就称之为IOC容器
2、依赖注入
review:
-
Servlet生命周期中的初始化方法: init() , init(config)
public void init(ServletConfig config) throws ServletException {
this.config = config ;
init();
}
因此,如果我们需要在初始化时执行一些自定义的操作,那么我们可以重写无参的init方法。
我们可以通过getConfig()获取ServletConfig对象
可以通过config.getInitParameter()获取初始化参数
-
通过ServletContext获取配置的上下文参数
-
MVC : V:view 视图 ; C:Controller 控制器 ; M:Model 模型
模型有很多种类:数据访问模型(DAO);业务逻辑模型(BO);值对象模型(POJO);数据传输对象(DTO)
-
IOC
IOC - 控制反转 / DI - 依赖注入
控制反转:
- 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别;
如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别
- 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中
因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转
依赖注入:
- 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
那么,控制层和service层存在耦合。
- 之后,我们将代码修改成FruitService fruitService = null ;
然后,在配置文件中配置:
创建domcument的方法
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1、创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2、创建DocumentBuilder对象
DocumentBuilder documentBuilder = null;
try {
//3、创建Document对象
documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(resourceAsStream);
//4、获取所有bean节点
//根据标签名 根据 bean标签,来获取 一个 node集合
NodeList beanList = document.getElementsByTagName("bean");
不懂得问题
重定向的路径 / 这个问题好迷糊
为什么那个反射 可以传object数组进去 懂了
我想知道在总控servlet里面使用return为什么不会是程序结束,我想在好像懂了一些,他也是servlet,执行完了就退出,我想找个时间,重新写一下那个手写web服务器
八、filter
1、 成为filter 要这样
2、 filter放行
FilterChain filterChain 这个意思是过滤器链条
放行
xxxx(放行前执行这条)
filterChain.doFilter(req,resp)
xxxx(放行后 它回来了 执行这条)
3、 @WebFilter(这里要写的和servlet一样,不然怎么拦截?)
4、 配置文件写法
5、 扩大拦截范围
6、 过滤器链条
7、 过滤器链条执行顺序
1、注解方式 按照全类名字母顺序决定的
2、配置文件 是按照配置文件 写的先后顺序 谁先配置的先拦截谁
8、 应用
把设置编码做成过滤器放在前面
记得把servlet转换成HTTPservlet
9、 容易错的地方
记得写过滤器的时候,就算什么都没干,也要先把放行写了,类似与Mabits里面的close和 commit
10、 把编码格式写到文件里,不把他写死
11、我犯的错误
1、 servlet里面的urlPattern 要加/
@WebServlet("/demo.do")
2、过滤器里面的初始化方法和销毁方法,要把super那个去掉??
报错原因
原因是,过滤器中没有重写public void init()和 public void destroy() 方法,jdk 1.9 之后,可以不写这两个方法,如果用jdk1.8必须要写。
注意:
不能直接使用快速生成代码的重写方法,要把init和destroy() 里面的super都删掉,当然不删destroy中的依旧可以启动
3、转发那里,写的是 succ 但是我要转到的是succ.html 这是个错误
4、配置文件不会写
应该像filter标签,不能写servlet
然后 url-pattern 不能写引号
5、这行报错,不能转换空值为httpservletRequest
(HttpServletRequest)servletRequest.setCharacterEncoding("utf-8");
需要套两个括号,我超
((HttpServletRequest)servletRequest).setCharacterEncoding("utf-8");
九、事务管理(不是service里面的事务管理)
1,引出问题
这意味着我的三个da里面的连接都需要用一个,用面向对象的方法,就是传参数
话说,我之前就是这么解决的
2、引出方法
3、实现方法
1、在filters 里面 新建个类 实现Filters 方法
OpenSessionInViewFilter
拦截 *.do
2、获取conn 对象
建了个包 trans 建了个类 TransactionManager
conn从ThreadLocal里面获取,
如果connection 不为空 就把他的自动提交设置为null
如果conn为空,就说明现在没有连接,我们就需要获取一个连接
老师是用JDBC的方法写的,而且没有把获取conn 抽取出去,需要把conn抽取出来,成为一个工具类,通过这个工具类获取连接,就像我的Mybatis里面的这个方法一样
老师的获取驱动类
这样当ThreadLocal 里面没有conn 的时候,就可以获取到连接了,老师精简了下代码
3、提交和回滚方法
但是三个方法里面这个步骤 获取conn对象 是一样的
所以要把它提取到获取连接的那个类里面去
3、获取conn抽取到 获取连接的工具类里面
注意静态 static 问题
1、把那个ThreadLocal 放到了 工具类里面
2
3!在这里插入图片描述
这个方法也太NB了吧
4、那三个方法就变成这样了
4、吐了,这只是基础的
比如说事务,两个业务方法包含的时候,这个就比较复杂,称为事务的传播机制
5、要去掉BaseDao里面的close方法
我写的mybatis的方法,所以要注释掉这个 session.close() 在这里关闭就完了
6、开始写了
在这个过滤器里面调用那个 事务类的方法,他把他写成静态的了
这么写
7、从threadLocal中移除conn方法
注意这个方法不严谨,应该写这个 threadLocal.remove
添加链接描述
8、之后就是实验
故意写错,让他回滚,但是程序结果就会出错,原因是程序内部出错了,没有把错误抛出来,而是try catch了,需要把所有try catch 取消掉,然后把错误都抛出来
它在add 方法里 在调用DAO层的 edit方法,让edit的语句出错,同时回滚掉add添加的数据
好耶,我也模拟出来了,数据库添加成功,但是编辑报错,没有回滚掉add
就是错误被内部给catch了,所以它提交了,没有回滚
DAO层的try catch全删
9、老师不是吧try catch 全删了,保留 一部分 try catch 并且向外抛异常
老师这里没有直接抛异常而是 新建了一个异常类原因如下
干,我不会重写RuntimeException方法
1、原来是在构造方法里面写
2、日,原来super(直接就可以写)
3、干,我写了忘记抛了
成功了
卧槽后面还有配置式和注解式的事务管理??
10.在git分支合并那里有不会的东西
添加链接描述
十、ThreadLocal中的get和 set源码分析
set方法
我之前搞不懂,ThreadLocal 是怎么区分 我要的是哪个值得,这下明白了,原来是通过threadLocal 1 threadLocal 2 threadLocal 3
这样分辨的
2) ThreadLocal
- get() , set(obj)
- ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据
- set方法源码分析:
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap)
if (map != null)
map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)
else
createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化
}
get方法
@SuppressWarnings(“unchecked”)
告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
-get方法源码分析:
public T get() {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带
if (e != null) {
@SuppressWarnings(“unchecked”)
T result = (T)e.value; //entry.value就可以获取到工具箱了
return result;
}
}
return setInitialValue();
}
每一个threadMap 里面只有一对值、
添加链接描述
十一、Listener 一共有八个
1. 监听器
1) ServletContextListener - 监听ServletContext对象的创建和销毁的过程
2) HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
3) ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程
4) ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
5) HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
6) ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)
7) HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
8) HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化
2. 新建
3. 配置方法
4. 应用
5. 在水果管理系统的应用
从上下文里面获取过来
这样就不是当场new了,而是从作用域里面获取
6. 为什么这么做
因为dispatcherServlet 1、MVC 中间的角色 2、只是负责转发
而IOC容器 1、是所有组件的管理2、是控制层 业务逻辑层 数据访问层 以及这些层依赖关系的一个注入
IOC容器他的角色要比中央控制器大多了
7.优化硬编码 这里有些语法我没懂,我要先把它记录下来
8.自己写
1、干,监听器我不会写
Listener
我实现了方法,他怎么没让我重写啊
好像要自己手动敲上去
2、名字冲突
3、但还是出错
啊,我好想没有给监听器 设置路径
4、我把这两个弄混了
@WebFilter
@WebListener
5、我靠 我的ClassPathXmlApplicationContext和老师的不一样
老师的把获取那个 NodeList beanList 这个东西放在构造方法里面了,我直接放在 public Object getBean(String name) { 这个方法里面了,年轻啊
6、沃日,不一样的也太多了吧
老师是这样的
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String,Object> beanMap = new HashMap<>();
private String path = "applicationContext.xml" ;
public ClassPathXmlApplicationContext(){
this("applicationContext.xml");
}
public ClassPathXmlApplicationContext(String path){
if(StringUtil.isEmpty(path)){
throw new RuntimeException("IOC容器的配置文件没有指定...");
}
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for(int i = 0 ; i<beanNodeList.getLength() ; i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element)beanNode ;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class beanClass = Class.forName(className);
//创建bean实例
Object beanObj = beanClass.newInstance() ;
//将bean实例对象保存到map容器中
beanMap.put(beanId , beanObj) ;
//到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置
}
}
//5.组装bean之间的依赖关系
for(int i = 0 ; i<beanNodeList.getLength() ; i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
NodeList beanChildNodeList = beanElement.getChildNodes();
for (int j = 0; j < beanChildNodeList.getLength() ; j++) {
Node beanChildNode = beanChildNodeList.item(j);
if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
Element propertyElement = (Element) beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
//1) 找到propertyRef对应的实例
Object refObj = beanMap.get(propertyRef);
//2) 将refObj设置到当前bean对应的实例的property属性上去
Object beanObj = beanMap.get(beanId);
Class beanClazz = beanObj.getClass();
Field propertyField = beanClazz.getDeclaredField(propertyName);
propertyField.setAccessible(true);
propertyField.set(beanObj,refObj);
}
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}
我是这样的
public class ClassPathXmlApplicationContext implements BeanFactory{
private Map<String,Object> beanMap=new HashMap<String,Object>();
String path="applicationContext.xml";
@Override
public Object getBean(String name) {
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1、创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2、创建DocumentBuilder对象
DocumentBuilder documentBuilder = null;
try {
//3、创建Document对象
documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(resourceAsStream);
//4、获取所有bean节点
//根据标签名 根据 bean标签,来获取 一个 node集合
NodeList beanList = document.getElementsByTagName("bean");
//然后循环这个集合
for (int i = 0; i < beanList.getLength(); i++) {
//这里面不叫get,叫item
Node beanNode = beanList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
//这个是 向上转型,用子类里面的方法
Element beanElement = (Element) beanNode;
String id = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
//id对应实例对象
Class<?> aClass = Class.forName(className);
Object beanObj = aClass.newInstance();
//把值放进去之后,再往集合里面放
beanMap.put(id, beanObj);
//我觉的要从这里开始,毕竟我要从map里面取对象
}
}
for (int i = 0; i < beanList.getLength(); i++) {
Node item = beanList.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) item;
NodeList childNodes = element.getChildNodes();
if(childNodes.getLength()!=0){
String objectId = element.getAttribute("id");
Object thisObj = beanMap.get(objectId);
for (int j = 0; j < childNodes.getLength(); j++) {
Node item1 = childNodes.item(j);
if (item1.getNodeType() == Node.ELEMENT_NODE&&item1.getNodeName().equals("property")) {
Element element1=(Element) item1;
String propertyName = element1.getAttribute("name");
String propertyRef = element1.getAttribute("ref");
//这个beanObj 不能找错了
Class<?> aClass = thisObj.getClass();
Field declaredField = aClass.getDeclaredField(propertyName);
declaredField.setAccessible(true);
Object beanObject = beanMap.get(propertyRef);
//这步值应该就赋值进去了
declaredField.set(thisObj,beanObject);
}
}
}
}
}
} catch (ParserConfigurationException | IOException | SAXException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Object o = beanMap.get(name);
return o;
}
}
…我不知道之前有没有代码 写的这样 烂得离谱
7、无参调有参
添加链接描述
8、我靠我没有配置上下文初始ICO配置文件参数,我的tomcat直接启动不了
9、来吧,快三点了,整理完这个就睡觉
1、我说不太好,我直接写代码吧 改造beanFactory 实现类
public class ClassPathXmlApplicationContext implements BeanFactory{
private Map<String,Object> beanMap=new HashMap<String,Object>();
//这里给个默认值
String path="applicationContext.xml";
//老师说过 框架都是用无参构造去反射的,如果不写无参构造,框架就会报错
//我可能需要无参构造去 用来反射,但是我这个月无参构造没有用,我需要调用下面的有参构造,
//所以只能这么写了
public ClassPathXmlApplicationContext() {
this("applicationContext.xml");
}
public ClassPathXmlApplicationContext(String path) {
if(StringUtils.isNull(path)){
throw new RuntimeException("ICO配置文件参数出错");
}
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(path);
//1、创建DocumentBuilderFactory
2、改造触发器 listener 这个类
public class ContextListen implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
String path = servletContext.getInitParameter("contextConfigLocation");
//注意如果这里的path 不写,那么就会默认调用无参构造,无参构造里面已经指定参数了
//我这里如果没有获取到初始化参数,tomcat直接启动不了,老师那里却能启动,并且报错??
BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);
servletContext.setAttribute("beanFactory",beanFactory);
}
3、设置初始化参数
contextConfigLocation
applicationContext.xml
这里报错不用管,老师说idea可能认为这是个spring配置文件,但是却不是
十二、复习
1、连接数据库
2、界面 thymeleaf
3、做了带有分页的
4、添加了根据关键字查询
5、对MCV结构进行优化
servlet->switch case ->反射(reflect)->提取dispatcherServlet(中央控制器)
servlet->controller
controller(1、获取参数2、业务处理3、视图资源转发) 抽取(1,2)->dispatcherServlet
service(多个单精度dao组合而成)
降低耦合,IOC容器 1、生命周期控制翻转到IOC容器 2、依赖注入
过滤器,监听器
事务管理(transaction)connection共享->ThreadLocal(OpenSessionViewFilter 过滤器事务)
TransactionManager(重复代码抽取->connUtil)
ThreadLocal源码
十三、cookie了解
这部分的知识点,滚来滚去都要滚烂了
1、概念:
1、cookie是浏览器端保存一些数据,适当的时候,把保存的数据发给服务器
2、SessionId是以cookie的形式保存的
3、不同网站的cookie 不会共享
2、创建cookie
3、向客服端发送cookie,让客服端保存cookie
请求头携带了cookie
响应头发送了cookie
请求头和响应头都携带了cookie
4、设置cookie的有效时长
cookie.setMaxAge(20); 这个单位是秒
60*60*24*7 cookie保存7天
5、对cookie进行细分
6、一般情况下不用设置这么细
这两个方法,我都没有用过,是在同一服务器的不同文件夹网站,或者跨域的情况下使用的,如果要使用的话,参考,自己再d多搜一搜
添加链接描述
添加链接描述
7、十天免登陆
1、客服端想服务端发送请求,会把cookie带过去,服务器去cookie里面取,看能不能取到10天免登陆的flag,如果有这种flag为true,表示曾经勾选过十天免登陆。
2、尝试去找Key 用户名 Value kerwin Key 密码 Value 123456 ,然后去后台验证,验证通过之后直接跳转首页
8、session 与 cookie 的区别
cookie客户端保存在本地,session保存在服务器
8、!!!切记,更新了cookie,比如时间,立即销毁cookie一定要把cookie发过去,更新浏览器的cookie
我在这里吃过大亏
resp.addCookie(cookie)
我在html设置了页面加载好的时候
自动访问servle
然后servlet里面判断如果 没有10天为登录的cookie
就会跳转到主页上
然后他两就这样转起来了
9、webStorage
十四、VUE快速学习
我还是挺喜欢这节课的
1、那个神奇的scope 完成了对象属性发送的
这是个引子,自己慢慢搜索
添加链接描述
这个东西叫vue 插槽
好像和我想的不一样
算了,这部分先不学了,用的时候再说吧
2、导入js文件
<script type="text/javascript" src="js/vue.js"></script>
3、当页面加载完成的时候
window.οnlοad=function(){
}
window.οnlοad=function(){
var vue=new Vue({ })
}
这个括号里面就是键值对 Key:value
不能把方法和属性声明 放在window.onload里面
Vue就是一个对象,类似这个
犯得错误:javascript 创建对象是 new Object; javascript创建对象的方法
javascript创建对象的方法。。添加链接描述
怎么定义对象方法。。
var person1={
name:"kerwin1",
age:181,
sayHello:function (){
alert(person1.name+" sayHello");
}
}
怎么绑定成员方法…
document.getElementById("hello").onclick=person1.sayHello;
加不加括号,好像就是加了()就是把返回值赋给这个对象
添加链接描述
添加链接描述
4、新建Vue对象
0、这里面的属性左边加不加 “” 都可以
1、el是element的意思
2、data数据 绑定
1、{{}}
{{ value }} 这个代表和el里面的data里面的属性绑定
<script type="text/javascript" src="/js/vue.js"></script>
</head>
<body>
<div id="div0">
<p>{{msg}}</p>
</div>
</body>
<script type="text/javascript">
var vue=new Vue({
el:"#div0",
data:{
msg:"hello"
}
});
</script>
2、v-bind
v-bind:value 表示绑定 value属性,v-bind 可以省略,也就是 :value
{{msg}}
你可能感兴趣的:(java)