JavaWeb全新总结
Thymeleaf-Vue
web项目搭建流程
### JDBCUtils
导入德鲁伊线程池jar包,创建properties文件
username=root
password=zmj.666.999
url=jdbc:mysql://localhost:3306/jdbctest?serverTimezone=UTC
driverClass=com.mysql.jdbc.Driver
创建数据连接
public class DruidUtils {
public static Connection getDruidConnection() throws Exception{
Properties properties = new Properties();
Class clazz = Class.forName("jdbcUtils.DruidUtils");
ClassLoader classLoader = clazz.getClassLoader();
InputStream ras = classLoader.getResourceAsStream("druid.properties");
properties.load(ras);
DataSource source = DruidDataSourceFactory.createDataSource(properties);
Connection conn = source.getConnection();
return conn;
}
}
DAO
JavaBean
根据数据库表的设计,建造与表一一对应的JavaBean类
package bean;
/**
* Created by KingsLanding on 2022/7/12 23:50
*/
public class Massage {
private Integer id;
private String name;
private Integer age;
private String phone;
public Massage() {
}
public Massage(Integer id, String name, Integer age, String phone) {
this.id = id;
this.name = name;
this.age = age;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Massage{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", phone='" + phone + '\'' +
'}';
}
}
DbUtils
用于操作数据库的工具类,使用前首先需要导入DbUtils的jar包
功能接口
- 根据所需功能,创建功能接口,每个表对应一个功能接口
/**
* Created by KingsLanding on 2022/7/12 23:52
*/
public interface MassageQuery {
/**
* 通过id查询一条数据
* @param id
* @return
*/
public Massage getMassageOne(String sql,Integer id);
/**
* 通过id查询多条数据
* @param id
* @return
*/
public List<Massage> getMassageMore(String sql,Integer id);
/**
* 获取Massage表中的所有数据
* @param sql
* @return
*/
public List<Massage> getMassageAll(String sql);
/**
* 获取表中有多少条数据
* @param sql
* @return
*/
public Long getMassageCount(String sql);
/**
* 增加一条数据
* @param sql
* @param massage
* @return
*/
public int addMassage(String sql,Massage massage);
/**
* 更新一条数据
* @param sql
* @param massage
* @return
*/
public int updateMassage(String sql,Massage massage);
/**
* 删除一条数据
* @param sql
* @param id
* @return
*/
public int deleteMassage(String sql,Integer id);
}
- 实现该功能接口
/**
* Created by KingsLanding on 2022/7/12 23:56
*/
public class MassageImpl implements MassageQuery {
@Override
public Massage getMassageOne(String sql, Integer id) {
Connection conn = null;
Massage query = null;
try {
conn = DruidUtils.getDruidConnection();
System.out.println(conn);
QueryRunner runner = new QueryRunner();
BeanHandler<Massage> handler = new BeanHandler<>(Massage.class);
query = runner.query(conn, sql, handler, id);
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return query;
}
@Override
public List<Massage> getMassageMore(String sql, Integer page) {
Connection conn = null;
List<Massage> query = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
BeanListHandler<Massage> handler = new BeanListHandler<>(Massage.class);
query = runner.query(conn, sql, handler, page);
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return query;
}
@Override
public List<Massage> getMassageAll(String sql) {
Connection conn = null;
List<Massage> query = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
BeanListHandler<Massage> handler = new BeanListHandler<>(Massage.class);
query = runner.query(conn, sql, handler);
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return query;
}
@Override
public int addMassage(String sql, Massage massage) {
Connection conn = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
runner.update(conn, sql, massage.getId(), massage.getName(), massage.getAge(), massage.getPhone());
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return 0;
}
@Override
public int updateMassage(String sql, Massage massage) {
Connection conn = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
runner.update(conn,sql,massage.getName(),massage.getAge(),massage.getPhone(),massage.getId());
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return 0;
}
@Override
public int deleteMassage(String sql, Integer id) {
Connection conn = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
runner.update(conn,sql,id);
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return 0;
}
public Long getMassageCount(String sql){
Connection conn = null;
Long query = null;
try {
conn = DruidUtils.getDruidConnection();
QueryRunner runner = new QueryRunner();
ScalarHandler handler = new ScalarHandler();
query = (Long)runner.query(conn, sql, handler);
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return query;
}
}
Service层(这里我写的有问题)
/**
* Created by KingsLanding on 2022/7/14 17:57
*/
public interface MassageServiceInterface {
/**
* 查询所有数据
* @return
*/
public List<Massage> getMassageData();
/**
* 修改一条数据
* @param massage
*/
public void updateMassageData(Massage massage);
/**
* 获取一条数据
* @param id
* @return
*/
public Massage getMassageOneData(Integer id);
/**
* 添加一条数据
* @param massage
*/
public void addMassageOneData(Massage massage);
/**
* 删除一条数据
* @param id
*/
public void deleteMassageOneData(Integer id);
/**
* 查询指定数量的数据,分页功能
* @param pageNo
* @return
*/
public List<Massage> getMassagePage(Integer pageNo);
/**
* 查询表总数据条数
* @return
*/
public Long getMassageCount();
}
- 接口实现
/**
* Created by KingsLanding on 2022/7/13 11:40
*/
public class MassageService implements MassageServiceInterface{
MassageQuery massageQuery=new MassageImpl();
public List<Massage> getMassageData(){
String sql="select id,name,age,phone from massage";
List<Massage> list = massageQuery.getMassageAll(sql);
System.out.println(list);
return list;
}
public List<Massage> getMassagePage(Integer pageNo){
String sql="select * from massage limit ?,3";
List<Massage> massageMore = massageQuery.getMassageMore(sql,(pageNo-1)*3);
return massageMore;
}
public void updateMassageData(Massage massage){
String sql="update massage set name=?,age=?,phone=? where id=?";
massageQuery.updateMassage(sql,massage);
}
public Massage getMassageOneData(Integer id){
String sql="select id,name,age,phone from massage where id=?";
Massage massageOne = massageQuery.getMassageOne(sql, id);
return massageOne;
}
public void addMassageOneData(Massage massage){
String sql="insert into massage(id,name,age,phone)value(?,?,?,?)";
massageQuery.addMassage(sql,massage);
}
public void deleteMassageOneData(Integer id){
String sql="delete from massage where id=?";
massageQuery.deleteMassage(sql,id);
}
public Long getMassageCount(){
String sql="select count(*) from massage";
Long massageCount = massageQuery.getMassageCount(sql);
return massageCount;
}
}
Servlet
- 为了使用
Thymeleaf渲染页面
首先导入ViewBaseServlet类,导入Thymeleafjar包
package mySpringmvc;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
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.IOException;
import java.lang.reflect.Method;
public class ViewBaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
String action = req.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// System.out.println(method);
// 调用目标业务 方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
- 配置xml文件
<!--
根据逻辑视图名称 得到 物理视图名称
此处的视图名称是 index
那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
逻辑视图名称 : index
物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
所以真实的视图名称是: / index .html
-->
<!-- 配置上下文参数 -->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
</web-app>
- 使用这种方式时,请求i转发的语句是这样的:
super.processTemplate("index",req,resp);
调用一个servlet中的不同方法的方式
switch - case
String action = req.getParameter("action");
if(StringUtils.isEmpty(action)){
action="indexPage";
}
switch (action){
case "index":
index(req,resp);
break;
case "indexPage":
indexPage(req,resp);
break;
case "update":
update(req,resp);
break;
case "getMassageOne":
getMassageOne(req,resp);
break;
case "add":
add(req,resp);
break;
case "delete":
delete(req,resp);
break;
default:
throw new RuntimeException("action值非法");
}
}
使用反射,动态获取运行时类的方法
String action = req.getParameter("action");
if(StringUtils.isEmpty(action)){
action="indexPage";
}
//使用反射,动态获取运行时类的方法
Method[] methods = this.getClass().getDeclaredMethods();
for (Method m : methods){
//获取方法名
String methodName = m.getName();
//判断方法名与action值是否相同
if(action.equals(methodName)){
m.setAccessible(true);
try {
//通过反射技术调用该方法
m.invoke(this,req,resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
throw new RuntimeException("action值非法");
方法举例
private void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Massage> massageData = massageService.getMassageData();
HttpSession session = req.getSession();
System.out.println(massageData);
//2.把全部信息保存到Session域中
session.setAttribute("massageData",massageData);
//此处的视图名称是 index
//那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
//逻辑视图名称 : index
//物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是: / index .html
super.processTemplate("index",req,resp);
}
private void indexPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
int pageNo = Web_Util.parseInt(req.getParameter("pageNo"), 1);
// HttpSession sessionPage = req.getSession();
// sessionPage.setAttribute("pageNo",pageNo);
// Integer pageNo =1;
// String pageNoStr = req.getParameter("pageNo");
// if(StringUtil.isNotEmpty(pageNoStr)){
// pageNo=Integer.parseInt(pageNoStr);
// }
HttpSession session = req.getSession();
session.setAttribute("pageNo",pageNo);
Long massageCount = massageService.getMassageCount();
int pageCount=(massageCount.intValue()+5-1)/5;
session.setAttribute("pageCount",pageCount);
List<Massage> massagePage = massageService.getMassagePage(pageNo);
System.out.println(massagePage);
session.setAttribute("massagePage",massagePage);
super.processTemplate("indexPage",req,resp);
}
private void getMassageOne(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
String StrId = req.getParameter("id");
if(StringUtil.isNotEmpty(StrId)){
int id = Integer.parseInt(StrId);
Massage massageOneData = massageService.getMassageOneData(id);
System.out.println(massageOneData);
//保存到request中
req.setAttribute("massageOneData",massageOneData);
//资源跳转
super.processTemplate("update",req,resp);
}
}
引入DispatcherServlet中央控制器
通过读取applicationContext.xml文件、将中央控制器DispatcherServlet和对应的Controller关联起来
优势:避免过多的Servlet类文件,用一个Servlet控制相关功能组件,核心是利用反射原理,获取不同的属性节点
DispatcherServlet这个类的工作分为两大部分:
1.根据url定位到能够处理这个请求的controller组件:
1)从url中提取servletPath : /fruit.do -> fruit
2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中
<bean id="fruit" class="com.atguigu.fruit.controllers.FruitController/>
通过DOM技术我们去解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有的Controller组件
3)根据获取到的operate的值定位到我们FruitController中需要调用的方法
2.调用Controller组件中的方法:
1) 获取参数
获取即将要调用的方法的参数签名信息: Parameter[] parameters = method.getParameters();
通过parameter.getName()获取参数的名称;
准备了Object[] parameterValues 这个数组用来存放对应参数的参数值
另外,我们需要考虑参数的类型问题,需要做类型转化的工作。通过parameter.getType()获取参数的类型
2) 执行方法
Object returnObj = method.invoke(controllerBean , parameterValues);
3) 视图处理
String returnStr = (String)returnObj;
if(returnStr.startWith("redirect:")){
....
}else if.....
/**
* Created by KingsLanding on 2022/7/16 16:12
*/
@WebServlet("/Massage")
public class DispatcherServlet extends ViewBaseServlet{
HashMap<String, Object> beanMap = new HashMap<>();
public DispatcherServlet() {
}
public void init() throws ServletException {
super.init();
try {
//解析applicationContext.xml文件
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点(即applicationContext.xml)中beans标签下的id="Massage" class="servlet.MassageController"
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 controllerBeanClass = Class.forName(className);
Object beanObj = controllerBeanClass.newInstance() ;
//将id中的Massage,class中的运行时类实例存到beanMap中
beanMap.put(beanId , beanObj) ;
}
}
} 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();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
req.setCharacterEncoding("UTF-8");
//假设URL是:http://localhost:8080/Massage.do
//那么servletPath是:/Massage.do
/*
思路:
一、/Massage.do --> Massage
二、 Massage ----> MassageController
*/
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
//去头去尾,没有就不用去
// int lastDotIndex = servletPath.lastIndexOf(".do");
// servletPath = servletPath.substring(0,lastDotIndex);
//Map的查询方法:get(Object key),通过key查询value---此时的controllerBeanObj就是对应的类
Object controllerBeanObj = beanMap.get(servletPath);
String action = req.getParameter("action");
if(StringUtils.isEmpty(action)){
action="indexPage";
}
/* 通过反射获取指定的method
try {
Method method = controllerBeanObj.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(controllerBeanObj,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {e.printStackTrace();
e.printStackTrace();
}
*/
//使用反射,动态获取运行时类controllerBeanObj的方法
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for (Method method : methods){
//获取方法名
String methodName = method.getName();
//判断方法名与action名是否相同
if(action.equals(methodName)){
//确保方法可用(爆破)
method.setAccessible(true);
try {
//通过反射技术调用controller中的方法
//这里的返回值是执行方法,方法的返回值(也就是返回的一个标识)
Object returnObj = method.invoke(controllerBeanObj, req);
//3.视图处理
//将这个标签进行强转为String类型
String methodReturnStr = (String)returnObj ;
//如果返回值以redirect:开头
if(methodReturnStr.startsWith("redirect:")){ //比如: redirect:Massage
//此处是将redirect:后面的截取不要
String redirectStr = methodReturnStr.substring("redirect:".length());
//如果是返回redirect:开头的String值,先将redirect:截取,然后执行response重定向,目标就是
//截取后的Massage
resp.sendRedirect(redirectStr);
}else{//如果不是以redirect:开头;那就执行资源跳转方法,目标就是返回的String值methodReturnStr
super.processTemplate(methodReturnStr,req,resp); // 比如: "edit"
}
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
throw new RuntimeException("action值非法");
}
}
那么之前的Servlet就成为一个普通方法类Controller
下面这个示例中没有将参数的获取抽取到中央控制器中,,只是将方法的定位和试图处理抽取到了中央控制器中,没有完全完成
/**
* Created by KingsLanding on 2022/7/13 11:38
*/
//@WebServlet("/Massage")
/*
去掉这个注解,就相当于没有在web.xml文件里配置,那么这个类就不在是一个Servlet了
此时MassageController类继承了ViewBaseServlet,但是它本身不是Servlet,所以不会调用ViewBaseServlet
中的init()方法了
*/
public class MassageController {
MassageServiceInterface massageService = new MassageService();
private String index(HttpServletRequest req) throws ServletException, IOException {
List<Massage> massageData = massageService.getMassageData();
HttpSession session = req.getSession();
System.out.println(massageData);
//2.把全部信息保存到Session域中
session.setAttribute("massageData",massageData);
//此处的视图名称是 index
//那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
//逻辑视图名称 : index
//物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是: / index .html
// super.processTemplate("index",req,resp);
return "index";
}
private String indexPage(HttpServletRequest req) throws IOException{
int pageNo = Web_Util.parseInt(req.getParameter("pageNo"), 1);
// HttpSession sessionPage = req.getSession();
// sessionPage.setAttribute("pageNo",pageNo);
// Integer pageNo =1;
// String pageNoStr = req.getParameter("pageNo");
// if(StringUtil.isNotEmpty(pageNoStr)){
// pageNo=Integer.parseInt(pageNoStr);
// }
HttpSession session = req.getSession();
session.setAttribute("pageNo",pageNo);
Long massageCount = massageService.getMassageCount();
int pageCount=(massageCount.intValue()+5-1)/5;
session.setAttribute("pageCount",pageCount);
List<Massage> massagePage = massageService.getMassagePage(pageNo);
System.out.println(massagePage);
session.setAttribute("massagePage",massagePage);
// super.processTemplate("indexPage",req,resp);
return "indexPage";
}
private String getMassageOne(HttpServletRequest req) throws IOException{
String StrId = req.getParameter("id");
if(StringUtil.isNotEmpty(StrId)){
int id = Integer.parseInt(StrId);
Massage massageOneData = massageService.getMassageOneData(id);
System.out.println(massageOneData);
//保存到request中
req.setAttribute("massageOneData",massageOneData);
//资源跳转
// super.processTemplate("update",req,resp);
}
return "update";
}
private String update(HttpServletRequest req){
//注入数据
Massage massage = Web_Util.InputForBeanUtil(new Massage(), req.getParameterMap());
massageService.updateMassageData(massage);
//重定向,重新给Massage发送请求,重新获取massage数据,覆盖到index页面
// resp.sendRedirect("Massage");
return "redirect:Massage";
}
private String add(HttpServletRequest req) throws ServletException {
Massage massage = Web_Util.InputForBeanUtil(new Massage(), req.getParameterMap());
massageService.addMassageOneData(massage);
// resp.sendRedirect("Massage");
return "redirect:Massage";
}
private String delete(HttpServletRequest req) throws IOException{
Massage massage = Web_Util.InputForBeanUtil(new Massage(), req.getParameterMap());
massageService.deleteMassageOneData(massage.getId());
// resp.sendRedirect("Massage");
return "redirect:Massage";
}
}
拦截器Filter
/**
* Created by KingsLanding on 2022/7/22 13:02
*/
@WebFilter("/*")
public class CharFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截成功");
servletRequest.setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
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; 然后,在配置文件中配置:<bean id="fruit" class="FruitController"> <property name="fruitService" ref="fruitService"/> </bean>
BeanFactory
/**
* Created by KingsLanding on 2022/7/18 22:14
*/
public interface BeanFactory {
Object getBean(String id);
}
/**
* Created by KingsLanding on 2022/7/18 22:18
*/
public class ClassPathXmlContext implements BeanFactory {
private Map<String,Object> beanMap=new HashMap<>();
private String path;
public ClassPathXmlContext(){
this.path="applicationContext.xml";
}
public ClassPathXmlContext(String path){
if (StringUtil.isEmpty(path)){
throw new RuntimeException("IOC容器的配置文件没有指定");
}
try {
//解析applicationContext.xml文件
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节点(即applicationContext.xml)中beans标签下的id="Massage" class="servlet.MassageController"
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() ;
//将id中的Massage,class中的运行时类实例存到beanMap中
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 beanChildNodesList = beanElement.getChildNodes();
for (int j=0;j<beanChildNodesList.getLength();j++){
Node beanChildNode = beanChildNodesList.item(j);
if (beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
Element propertyElement = (Element)beanChildNode;
String propertyName = propertyElement.getAttribute("name");
System.out.println(propertyName);
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);
}
}
监听器Listener
ServletContextListener - 监听ServletContext对象的创建和销毁的过程
HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程
ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)
HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化
监听上下文启动创建IOC容器
解耦操作,降低各层之间的耦合程度,其中一层出问题不会在编译期间对其他层造成影响
在xml文件中配置listener的上下文参数
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
对应的applicationContext.xml文件
<beans>
<bean id="MassageQuery" class="daoImpl.MassageImpl"/>
<bean id="MassageServiceInterface" class="service.MassageService">
<!--<!–property标签用来表示属性:name表示属性名;req表示引用其他bean的id值–>-->
<property name="MassageQuery" ref="MassageQuery"/>
</bean>
<!--这个bean标签的作用:在dispatcherServlet中的servletPath中涉及的名字对应的是Massage,
那么就要MassageController这个类进行处理-->
<bean id="Massage" class="servlet.MassageController">
<property name="MassageServiceInterface" ref="MassageServiceInterface"/>
</bean>
</beans>
创建IOC容器
/**
* Created by KingsLanding on 2022/7/21 12:51
*
*
* 监听上下文启动,在上下文启动的时候去创建IOC容器,然后将其保存到application作用域
* 然后中央控制器再从application作用域中获取IOC容器
*/
@WebListener
//另一种配置方式是配置xml文件的方式
/* <listener>
<listener-class>listener.ContextLoaderListener</listener-class>
</listener>
*/
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//1.获取ServletContext对象
ServletContext application = sce.getServletContext();
System.out.println("chuangjian");
//2.获取上下文的初始化参数
String path = application.getInitParameter("contextConfigLocation");
//3.创建IOC容器
BeanFactory beanFactory = new ClassPathXmlContext(path);
//4.将IOC容器保存到application作用域中
application.setAttribute("beanFactory",beanFactory);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
那么DispatcherServlet再次迭代
/**
* Created by KingsLanding on 2022/7/16 16:12
*/
@WebServlet("/Massage")
public class DispatcherServlet extends ViewBaseServlet{
// private Map<String,Object> beanMap=new HashMap<>();
private BeanFactory beanFactory;
public DispatcherServlet() {
}
public void init() throws ServletException {
super.init();
//之前是在此处主动创建IOC容器的,现在优化为从application作用域中获取
// beanFactory=new ClassPathXmlContext();
ServletContext application = getServletContext();
Object beanFactoryObj = application.getAttribute("beanFactory");
if (beanFactoryObj!=null){
beanFactory=(BeanFactory)beanFactoryObj;
}else {
throw new RuntimeException("IOC容器获取失败!");
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// req.setCharacterEncoding("UTF-8");
//假设URL是:http://localhost:8080/Massage.do
//那么servletPath是:/Massage.do
/*
思路:
一、/Massage.do --> Massage
二、 Massage ----> MassageController
*/
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
//去头去尾,没有就不用去
// int lastDotIndex = servletPath.lastIndexOf(".do");
// servletPath = servletPath.substring(0,lastDotIndex);
//Map的查询方法:get(Object key),通过key查询value---此时的controllerBeanObj就是对应的类
Object controllerBeanObj = beanFactory.getBean(servletPath);
String action = req.getParameter("action");
if(StringUtils.isEmpty(action)){
action="indexPage";
}
/* 通过反射获取指定的method
try {
Method method = controllerBeanObj.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(controllerBeanObj,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {e.printStackTrace();
e.printStackTrace();
}
*/
//使用反射,动态获取运行时类controllerBeanObj的方法
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for (Method method : methods){
//获取方法名
String methodName = method.getName();
//判断方法名与action名是否相同
if(action.equals(methodName)){
//确保方法可用(爆破)
method.setAccessible(true);
try {
//通过反射技术调用controller中的方法
//这里的返回值是执行方法,方法的返回值(也就是返回的一个标识)
Object returnObj = method.invoke(controllerBeanObj, req);
//3.视图处理
//将这个标签进行强转为String类型
String methodReturnStr = (String)returnObj ;
//如果返回值以redirect:开头
if(methodReturnStr.startsWith("redirect:")){ //比如: redirect:Massage
//此处是将redirect:后面的截取不要
String redirectStr = methodReturnStr.substring("redirect:".length());
//如果是返回redirect:开头的String值,先将redirect:截取,然后执行response重定向,目标就是
//截取后的Massage
resp.sendRedirect(redirectStr);
}else{//如果不是以redirect:开头;那就执行资源跳转方法,目标就是返回的String值methodReturnStr
super.processTemplate(methodReturnStr,req,resp); // 比如: "edit"
}
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
// throw new RuntimeException("action值非法");
}
}
事务管理
2. 事务管理
1) 涉及到的组件:
- OpenSessionInViewFilter
- TransactionManager
- ThreadLocal
- ConnUtil
- BaseDAO
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方法源码分析:
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();
}
Cookie
- 创建Cookie对象
- 在客户端保存Cookie
- 设置Cookie的有效时长 cookie.setMaxAge(60) , 设置cookie的有效时长是60秒 cookie.setDomain(pattern); cookie.setPath(uri);
- Cookie的应用:十天免登录 4-1: 记住用户名和密码十天 setMaxAge(60 * 60 * 24 * 10)
@WebServlet("/cookie01")
public class CookieServlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建一个Cookie对象
Cookie cookie = new Cookie("uname","jim");
//2.将这个Cookie对象保存到浏览器端
response.addCookie(cookie);
request.getRequestDispatcher("hello01.html").forward(request,response);
}
}
Kaptcha
- 为什么需要验证码
- kaptcha如何使用:
- 添加jar包
- 在web.xml文件中注册KaptchaServlet,并设置验证码图片的相关属性
- 在html页面上编写一个img标签,然后设置src等于KaptchaServlet对应的url-pattern
- kaptcha验证码图片的各个属性在常量接口:
Constants中 - KaptchaServlet在生成验证码图片时,会同时将验证码信息保存到session中 因此,我们在注册请求时,首先将用户文本框中输入的验证码值和session中保存的值进行比较,相等,则进行注册
验证码的配置
<!--验证码配置-->
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>abcdefg</param-value>
</init-param>
<init-param>
<param-name>kaptcha.noise.impl</param-name>
<param-value>com.google.code.kaptcha.impl.NoNoise</param-value>
</init-param>
<init-param>
<param-name>kaptcha.image.width</param-name>
<param-value>100</param-value>
</init-param>
<init-param>
<param-name>kaptcha.image.height</param-name>
<param-value>30</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.font.size</param-name>
<param-value>25</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.font.names</param-name>
<param-value>Courier</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.font.color</param-name>
<param-value>blue</param-value>
</init-param>
<init-param>
<param-name>kaptcha.word.impl</param-name>
<param-value>com.google.code.kaptcha.text.impl.DefaultWordRenderer</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptch.jpg</url-pattern>
</servlet-mapping>
<!--通过标签和xml文件中的配置,显示验证码的图片 -->
<img src="/kaptch.jpg">
获取真实的验证码信息
HttpSession session = req.getSession();
Object kaptcha_session= session.getAttribute("KAPTCHA_SESSION_KEY");
System.out.println(kaptcha_session);
正则表达式的使用三步骤:
1. 定义正则表达式对象
正则表达式定义有两个方式:
1) 对象形式
var reg = new RegExp("abc")
2) 直接量形式
var reg = /abc/;
3) 匹配模式:
- g 全局匹配
- i 忽略大小写匹配
- m 多行匹配
- gim这三个可以组合使用,不区分先后顺序
例如: var reg = /abc/gim , var reg = new RegExp("abc","gim");
2. 定义待校验的字符串
3. 校验
2)元字符
. , \w , \W , \s , \S , \d , \D , \b , ^ , $
3)[]表示集合
[abc] 表示 a或者b或者c
[^abc] 表示取反,只要不是a不是b不是c就匹配
[a-c] 表示a到c这个范围匹配
4) 出现的次数
* 表示多次 (0 ~ n )
+ 至少一次 ( >=1 )
? 最多一次 (0 ~ 1)
{n} 出现n次
{n,} 出现n次或者多次
{n,m} 出现n到m次
Axios
添加并引入axios的js文件
基本格式: axios().then().catch()
2. Axios
Axios是Ajax的一个框架,简化Ajax操作
Axios执行Ajax操作的步骤:
1. 添加并引入axios的js文件
2-1. 客户端向服务器端异步发送普通参数值
- 基本格式: axios().then().catch()
- 示例:
axios({
method:"POST",
url:"....",
params:{
uname:"lina",
pwd:"ok"
}
})
.then(function(value){}) //成功响应时执行的回调 value.data可以获取到服务器响应内容
.catch(function(reason){}); //有异常时执行的回调 reason.response.data可以获取到响应的内容
reason.message / reason.stack 可以查看错误的信息
异步请求示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="/vue_js/axios.min.js"></script>
<script language="JavaScript" src="/vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function(){
var vue = new Vue({
el:"#div0",
data:{
uname:"zmj",
pwd:"ok"
},
methods:{
axios01:function () {
axios({
method:"POST",
url:"axiosTest",
params:{
uname:vue.uname,
pwd:vue.pwd
}
}).then(function (value) {
console.log(value)
}).catch(function (reason) {
console.log(reason)
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios01" value="发送一个带普通请求参数值的异步请求"/>
</div>
</body>
</html>
/**
* Created by KingsLanding on 2022/7/24 13:24
*/
@WebServlet("/axiosTest")
public class AxiosTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uname = req.getParameter("uname");
String pwd = req.getParameter("pwd");
System.out.println(uname+"+"+pwd);
}
}
JSON
-
JSON是一种数据格式
-
JSON格式表示两个学员信息的代码如下: [{sid:"s001",age:18},{sid:"s002",age:19}]
-
JSON表达数据更简洁,更能够节约网络带宽
- 什么是JSON
JSON是一种数据格式
XML也是一种数据格式
XML格式表示两个学员信息的代码如下:
<students>
<student sid="s001">
<sname>jim</sname>
<age>18</age>
</student>
<student sid="s002">
<sname>tom</sname>
<age>19</age>
</student>
</students>
JSON格式表示两个学员信息的代码如下:
[{sid:"s001",age:18},{sid:"s002",age:19}]
- JSON表达数据更简洁,更能够节约网络带宽
- 客户端发送JSON格式的数据给服务器端
1) 客户端中params需要修改成: data:
2) 服务器获取参数值不再是 request.getParameter()...
而是:
StringBuffer stringBuffer = new StringBuffer("");
BufferedReader bufferedReader = request.getReader();
String str = null ;
while((str=bufferedReader.readLine())!=null){
stringBuffer.append(str);
}
str = stringBuffer.toString() ;
3) 我们会发现 str的内容如下:
{"uname":"lina","pwd":"ok"}
- 服务器端给客户端响应JSON格式的字符串,然后客户端需要将字符串转化成js Object
客户端中params需要修改成: data
发送一个带普通请求参数值的异步请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="/vue_js/axios.min.js"></script>
<script language="JavaScript" src="/vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function(){
var vue = new Vue({
el:"#div0",
data:{
uname:"zmj",
pwd:"ok"
},
methods:{
axios02:function () {
axios({
method:"POST",
url:"JSONTest",
data:{
uname:vue.uname,
pwd:vue.pwd
}
}).then(function (value) {
console.log(value)
}).catch(function (reason) {
console.log(reason)
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios02" value="发送一个带普通请求参数值的异步请求"/>
</div>
</body>
</html>
服务器响应json格式的数据给客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03.演示Axios发送异步请求给服务器端,服务器响应json格式的数据给客户端</title>
<script language="JavaScript" src="/vue_js/vue.js"></script>
<script language="JavaScript" src="/vue_js/axios.min.js"></script>
<script language="JavaScript">
window.onload=function(){
var vue = new Vue({
"el":"#div0",
data:{
uname:"lina",
pwd:"ok"
},
methods:{
axios03:function(){
axios({
method:"POST",
url:"JSONTest",
data:{
uname:vue.uname,
pwd:vue.pwd
}
})
.then(function (value) {
var data = value.data;
// data对应的数据:
// {uname:"鸠摩智",pwd:"ok"}
vue.uname=data.uname;
vue.pwd=data.pwd;
//此处value中的data返回的是 js object,因此可以直接点出属性
//如果我们获取的是一个字符串: "{uname:\"鸠摩智\",pwd:\"ok\"}"
//js语言中 也有字符串和js对象之间互转的API
//string JSON.stringify(object) object->string
//object JSON.parse(string) string->object
})
.catch(function (reason) {
console.log(reason);
});
}
}
});
}
</script>
</head>
<body>
<div id="div0">
uname:<input type="text" v-model="uname"/><br/>
pwd:<input type="text" v-model="pwd"/><br/>
<input type="button" @click="axios03" value="服务器响应json格式的数据给客户端"/>
</div>
</body>
</html>
JSONServlet
/**
* Created by KingsLanding on 2022/7/24 13:46
*/
@WebServlet("/JSONTest")
public class JSONServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader reader = req.getReader();
StringBuffer stringBuffer = new StringBuffer();
String str=null;
while ((str=reader.readLine())!=null){
stringBuffer.append(str);
}
str=stringBuffer.toString();
System.out.println(str);
//将String转化为Java object
Gson gson = new Gson();
//Gson有两个API
//1、fromJson(String,T)将字符串转化成java object
//2、toJson(java Object)将java Object转化为json字符串,这样才可以响应给客户端
JsonUser jsonUser = gson.fromJson(str, JsonUser.class);
System.out.println(jsonUser);
jsonUser.setUname("鸠摩智");
jsonUser.setPwd("123456");
//假设user是从数据库查询出来的,现在需要将其转化成json格式的字符串,然后响应给客户端
String userJsonStr = gson.toJson(jsonUser);
resp.setCharacterEncoding("UTF-8");
//MIME-TYPE
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write(userJsonStr);
}
}
Vue
1. Vue
1) {{}} - 相当于innerText
2) v-bind:attr 绑定属性值。例如,v-bind:value - 绑定value值
简写: :value
3) v-model 双向绑定
v-model:value , 简写 v-model
4) v-if , v-else , v-show
v-if和v-else之间不能有其他的节点
v-show是通过样式表display来控制节点是否显示
5) v-for 迭代
v-for={fruit in fruitList}
6) v-on 绑定事件
7) 其他:
- trim:去除首尾空格 , split() , join()
- watch表示侦听属性
- 生命周期
v-bind;v-model;v-if;v-else;v-show
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="../vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function () {
var vue = new Vue({
"el":"#div0",
data:{
msg:"hello",
name:"牛逼",
num:2,
}
});
}
</script>
</head>
<body>
<div id="div0">
<span>{{msg}}</span>
<!--v-bind:value表示绑定value属性,v-bind可以省略,变成:value --- 单向绑定-->
<input type="text" v-bind:value="name"><br>
<!--
v-model指的是双向绑定,之前的v-bind是通过msg这个变量来控制input的输入框
而v-model不仅由msg对象来控制input输入框,还可以反过来由input的内容来改变msg的值
-->
<input type="text" v-model:value="msg"><br>
<input type="text" v-model:value="num">
<!--v-if和v-else之间不能插入其他节点-->
<div v-if="num%2==0" style="width: 200px;height: 200px;background-color: brown;"></div>
<div v-else="num%2==0" style="width: 200px;height: 200px;background-color: aqua;"></div>
<!--v-show通过display来控制节点的显示-->
<div v-show="num%2==0" style="width: 200px;height: 200px;background-color: crimson ;"></div>
</div>
</body>
</html>
数据填充
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="../vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function () {
var vue=new Vue({
"el":"#div0",
data:{
fruitList:[
{fname:"苹果",price:4,fcount:100},
{fname:"香蕉",price:3,fcount:5},
{fname:"西瓜",price:4,fcount:34},
]
}
});
}
</script>
</head>
<body>
<div id="div0">
<table border="1" width="400" cellpadding="4" cellspacing="0">
<tr>
<th>名称</th>
<th>单价</th>
<th>库存</th>
</tr>
<!-- v-for表示迭代 -->
<tr align="center" v-for="fruit in fruitList">
<td>{{fruit.fname}}</td>
<td>{{fruit.price}}</td>
<td>{{fruit.fcount}}</td>
</tr>
</table>
</div>
</body>
</html>
侦听
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="../vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function(){
var vue = new Vue({
"el":"#div0",
data:{
num1:1,
num2:2,
num3:0
},
watch:{
//侦听属性num1和num2
//当num1的值有改动时,那么需要调用后面定义的方法 , newValue指的是num1的新值
num1:function(newValue){
this.num3 = parseInt(newValue) + parseInt(this.num2);
},
num2:function(newValue){
this.num3 = parseInt(this.num1) + parseInt(newValue) ;
}
}
});
}
</script>
</head>
<body>
<div id="div0">
<input type="text" v-model="num1" size="2"/>
+
<input type="text" v-model="num2" size="2"/>
=
<span>{{num3}}</span>
</div>
</body>
</html>
vue的生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="/vue_js/vue.js"></script>
<script language="JavaScript">
window.onload=function(){
var vue = new Vue({
"el":"#div0",
data:{
msg:1
},
methods:{
changeMsg:function(){
this.msg = this.msg + 1 ;
}
},
/*vue对象创建之前*/
beforeCreate:function(){
console.log("beforeCreate:vue对象创建之前---------------");
console.log("msg:"+this.msg);
},
/*vue对象创建之后*/
created:function(){
console.log("created:vue对象创建之后---------------");
console.log("msg:"+this.msg);
},
/*数据装载之前*/
beforeMount:function(){
console.log("beforeMount:数据装载之前---------------");
console.log("span:"+document.getElementById("span").innerText);
},
/*数据装载之后*/
mounted:function(){
console.log("mounted:数据装载之后---------------");
console.log("span:"+document.getElementById("span").innerText);
},
beforeUpdate:function(){
console.log("beforeUpdate:数据更新之前---------------");
console.log("msg:"+this.msg);
console.log("span:"+document.getElementById("span").innerText);
},
updated:function(){
console.log("Updated:数据更新之后---------------");
console.log("msg:"+this.msg);
console.log("span:"+document.getElementById("span").innerText);
}
});
}
</script>
</head>
<body>
<div id="div0">
<span id="span">{{msg}}</span><br/>
<input type="button" value="改变msg的值" @click="changeMsg"/>
</div>
</body>
</html>
前端Thymeleaf的基本用法
具体方法介绍:
heavy_code_industry.gitee.io/code_heavy_…
使用示例
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/index.css">
<script language="JavaScript" src="js/index.js"></script>
</head>
<body>
<div id="div_container">
<div id="div_fruit_list">
<p class="center f30">欢迎使用员工信息管理系统</p>
</div>
<div style="width: 60%;margin-left: 20%;text-align: right" >
<a th:href="@{/add.html}">添加数据</a>
</div>
<table id="tbl_fruit">
<tr>
<th class="w20">姓名</th>
<th class="w20">年龄</th>
<th class="w20">电话</th>
<th colspan="2">操作</th>
</tr>
<tr th:if="${#lists.isEmpty(session.massagePage)}">
<td colsapn="4">没有数据</td>
</tr>
<tr th:unless="${#lists.isEmpty(session.massagePage)}" th:each="massage : ${session.massagePage}">
<td><a th:text="${massage.name}" th:href="@{/update.do(id=${massage.id})}"></a></td>
<td th:text="${massage.age}"></td>
<td th:text="${massage.phone}"></td>
<td><a th:href="@{/Massage(id=${massage.id},action='getMassageOne')}">修改</a></td>
<td><a class="deleteMassage" th:onclick="|deleteMassage(${massage.id})|">删除</a></td>
</tr>
</table>
<div style="width: 60%;margin-left: 20%;padding-top: 5px" class="center">
<input type="button" value="首页" th:onclick="|page(1)|" th:disabled="${session.pageNo==1}">
<input type="button" value="上一页" th:onclick="|page(${session.pageNo - 1})|" th:disabled="${session.pageNo==1}">
<input type="button" value="下一页" th:onclick="|page(${session.pageNo + 1})|" th:disabled="${session.pageNo==session.pageCount}">
<input type="button" value="尾页" th:onclick="|page(${session.pageCount})|" th:disabled="${session.pageNo==session.pageCount}">
</div>
</div>
</div>
</body>
</html>