文章目录
- 一.`fruit`
- 二.`myssm`
- 三.WEB类
一.fruit
1.controller
调用fruitService
中的基本业务,实现封装的业务功能
1.1update()
private String update(Integer fid, String fname, Integer price, Integer fcount, String remark){
//更新数据库
fruitService.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//渲染页面,执行跳转
return "redirect:fruit.do";
}
1.2edit()
:发报机–>edit()
–>edit.html
–>update()
–>主界面
private String edit(Integer fid, HttpServletRequest req){
if(fid != null){
Fruit fruit = fruitService.getFruitByFid(fid);
req.setAttribute("fruit", fruit);
return "edit";
}
return "error";
}
1.3delete()
private String delete(Integer fid){
if(fid != null){
//删除数据库记录
fruitService.deleteFruit(fid);
//客户端重定向语句
return "redirect:fruit.do";
}
return "error";
}
1.4index()
private String index(String oper, String keyword,Integer pageNo, HttpServletRequest req){
//获取会话
HttpSession session = req.getSession();
if(pageNo == null){
pageNo = 1;
}
//判断是否为查询操作
if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){//搜索操作
//获取关键词
if(StringUtil.isEmpty(keyword)){
keyword = "";
}
//将关键词保存到session
session.setAttribute("keyword",keyword);
}else{//显示全部列表
//获取session关键词
Object keyObj = session.getAttribute("keyword");
if(keyObj == null){
keyword = "";
}else{
keyword = (String)keyObj;
}
//设置关键词
session.setAttribute("keyword", keyword);
}
//保存当前页码到session作用域
session.setAttribute("pageNo",pageNo);
keyword = (String)session.getAttribute("keyword");
//保存总页码到session作用域
int pageCount = fruitService.getPageCount(keyword);
session.setAttribute("pageCount",pageCount);
//从数据库读取fruitList
List<Fruit> fruitList = fruitService.getFruitList(keyword, pageNo);
//保存到session作用域
session.setAttribute("fruitList", fruitList);
//此处的视图名称为 index
//thymleaf会将 逻辑视图名称 对应到 物理视图名称 上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//super.processTemplate("index", request, response);
return "index";
}
1.5add()
:发报机–>add.html
–>add()
–>主界面
private String add(String fname, Integer price, Integer fcount, String remark){
//更新数据库
fruitService.addFruit(new Fruit(0,fname,price,fcount,remark));
//返回客户端重定向语句
return "redirect:fruit.do";
}
2.dao
:DAO(DataAccessobjects)
层
2.1FruitDAO
需要实现与数据库交互的基本功能:增删改查(总列表,单条记录,总数目)
public interface FruitDAO {
//获取指定页码的库存列表信息,每页显示5条
List<Fruit> getFruitList(String keyword, Integer pageNo);
//根据水果id获取库存信息
Fruit getFruitByFid(Integer fid);
//修改制定的库存记录
Boolean updateFruit(Fruit fruit);
//根据fid删除库存记录
Boolean delFruitById(Integer fid);
//添加新库存
Boolean addFruit(Fruit fruit);
//查询总记录条数的方法
int getFruitCount(String keyword);
}
2.2impl.FruitDAOImpl
2.2.1继承:BaseDAO<Fruit>
类 和 FruitDAO
接口
2.2.2实现:重写实现FruitDAO
中的方法
3.pojo
3.1Fruit
基本类,对应一张表
- 1.类的属性与表的列分别对应。
- 2.类的属性体现类之间的关系。
4.service
业务层
4.1FruitService
抽象类
public interface FruitService {
//获取指定页面的库存信息
List<Fruit> getFruitList(String keyword, Integer pageNo);
//添加库存记录
void addFruit(Fruit fruit);
//根据id查看库存信息
Fruit getFruitByFid(Integer fid);
//删除指定库存信息
void deleteFruit(Integer fid);
//获取总页数
Integer getPageCount(String keyword);
//修改特定库存记录
void updateFruit(Fruit fruit);
}
4.2FruitServiceImpl
实现类
调用fruitDAO
中的方法实现相应的功能
二.myssm
1.basedao
数据库交互包
1.1BaseDAO
数据库通用语句执行
构造器:
public BaseDAO() {
//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
//所以getGenericSuperclass()获取到的是BaseDAO的Class
Type genericType = getClass().getGenericSuperclass();
//ParameterizedType 参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
//获取到的<T>中的T的真实的类型
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new DAOException("BaseDAO 构造方法出错了,可能的原因是没有指定<>中的类型");
}
}
-
获取连接:
getConn()
调用ConnUtil
类中的获取连接方法,保证只有一个连接(为了方便事务管理中的回滚) -
~~关闭资源:
close()
~~取消该方法,方便事务管理 -
给预处理命令设置参数:
setParams(PreparedStatement psmt , Object... params)
-
执行更新数据库
executeUpdate(String sql , Object... params)
-
执行查询,返回一条记录:
load(String sql , Object... params)
//通过rs可以获取结果集的元数据 //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等 ResultSetMetaData rsmd = rs.getMetaData(); //获取结果集的列数 int columnCount = rsmd.getColumnCount(); if(rs.next()){ for(int i = 0 ; i<columnCount;i++){ String columnName = rsmd.getColumnName(i+1); //fid fname price Object columnValue = rs.getObject(i+1); //33 苹果 5 setValue(entity,columnName,columnValue); } }
-
执行查询,返回多条记录:
executeQuery(String sql , Object... params)
-
执行复杂查询,统计统计结果:
Object[] executeComplexQuery(String sql , Object... params)
-
通过反射技术给property属性赋值:
setValue(Object obj, String property, Object propertyValue)
1.2ConnUtil
数据库连接工具类
- 创建连接:
createConnection)()
- 获取连接:
getConnection()
从本地线程获取连接.若连接不存在,则创建连接并保存到本地线程. - 断开连接:
closeConn()
从本地线程获取连接,若连接存在,则关闭连接.
1.3DAOException
异常类型
定义一个DAOException异常
2.filters
过滤器的实现类包
包括初始化、过滤、销毁三个方法。
需要使用注解或者配置文件设置过滤对象:
//1.注解:
@WebFilter("*.do")
<!--2.xml文件-->
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.clucky.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.1CharacterEncodingFilter
设置编码
-
注解:拦截
*.do
结尾的请求
@WebFilter(urlPatterns = {“*.do”}, initParams = {@WebInitParam(name = “encoding”, value = “utf-8”)})
2. 初始化: 读取注解或者配置文件中的初始化参数设置编码*(可能是过滤器的初始化)*
```java
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String encodingStr = filterConfig.getInitParameter("encoding");
if(StringUtil.isNotEmpty(encodingStr)){
encoding = encodingStr;
}
}
-
过滤前后的语句: 设置编码
((HttpServletRequest)servletRequest).setCharacterEncoding(encoding);
2.2OpenSessionInViewFilter
事务管理(执行提交与回滚)
-
开启事务–>执行service–>执行完成提交事务
但是若事务执行异常–>回滚 -
try{ TransactionManager.beginTrans(); System.out.println("开启事务..."); filterChain.doFilter(servletRequest, servletResponse); TransactionManager.commit(); System.out.println("提交事务..."); } catch (Exception e) { e.printStackTrace(); try { TransactionManager.rollback(); System.out.println("回滚事务..."); } catch (Exception e1) { e1.printStackTrace(); System.out.println("回滚异常"); } }
-
需要
TransactionManage
的工具类进行管理事务的开启、提交、和回滚。
3.ioc(Inversion of Control)
控制反转or依赖注入(DI)
3.1BeanFactory
抽象类
3.2ClassPathXmlApplicationContext
实现类
3.2.1初始化:即构造器
-
利用
applicationContext.fxml
文件建立类与类之间的关系<?xml version="1.0" encoding="utf-8"?> <beans> <!-- 建立fruit和对应类的映关系,方便初始化的时候调用 --> <bean id="fruitDAO" class="com.atlff.fruit.dao.impl.FruitDAOImpl"></bean> <bean id="fruitService" class="com.atlff.fruit.service.impl.FruitServiceImpl"> <!-- 表示属性:name是属性名,ref表示引用其他bean的id --> <property name="fruitDAO" ref="fruitDAO"></property> </bean> <bean id="fruit" class="com.atlff.fruit.controllers.FruitController"> <property name="fruitService" ref="fruitService"></property> </bean> </beans>
-
获取配置文件的输入流,建立创建
Document
对象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);
-
获取
Bean
结点,创建相应的对象,放置到beanMap容器中
//4.获取所有bean结点
NodeList beanNodeList = document.getDocumentElement().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");//获取id属性
String className = beanElement.getAttribute("class");//获取class属性(返回字符串)
//利用反射得到bean对象
Class<?> beanClass = Class.forName(className);
Object beanObj = beanClass.newInstance();
//将bean对象保存到Map容器
beanMap.put(beanId, beanObj);
}
}
- 构建
Bean
结点之间的依赖关系
//5.组装bean之间的依赖关系
for (int i = 0; i < beanNodeList.getLength(); i++) {//遍历beanNodeList链表
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
NodeList beanChildNodeList = beanElement.getChildNodes();//获取bean元素的子结点
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);
}
}
}
}
3.2.2调用getBean
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
4.listeners
监听器
当对象发生时自动执行,类似于触发器。
功能:创建IOC
容器并容器保存到session
作用域,方便之后调用
注解:@WebListener
接口:ServletContextListener
方法实现:
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//1.获取ServletContext对象
ServletContext application = servletContextEvent.getServletContext();
//2.获取上下文的初始化参数
String path = application.getInitParameter("contextConfigLocation");
//3.创建IOC容器
BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);
//4.将IOC容器保存到application作用域
application.setAttribute("beanFactory", beanFactory);
}
5.myspringmvc
5.1DispatcherServlet
发报机,决定调用哪个组件
5.1.1注解@WebServlet("*.do")
用于响应浏览器的"*.do"
请求
5.1.2继承:ViewBaseServlet
5.1.3初始化方法:获取beanMap
容器
public void init() throws ServletException {
super.init();
//优化:可以在ContextListener中初始化给参数赋值
Object beanFactoryObj = getServletContext().getAttribute("beanFactory");
if(beanFactoryObj != null){
beanFactory = (BeanFactory)beanFactoryObj;
}else{
throw new RuntimeException("IOC容器获取失败!");
}
System.out.println("初始化完成!");
}
5.1.4service
方法
-
获取servlet的名字,决定调用哪个组件:
fruit.do --> fruit
//获取servlet的名字 String servletPath = req.getServletPath(); int lastDot = servletPath.lastIndexOf(".do"); servletPath = servletPath.substring(1, lastDot); //得到servlet名字对应的控制器类 Object contollerBeanObj = beanFactory.getBean(servletPath);
-
获取控制器中对应的方法:即操作“业务”
String operate = req.getParameter("operate"); if(StringUtil.isEmpty(operate)){ operate = "index"; }
-
利用反射调用
contollerBeanObj
中的operate
方法,并获取参数值,并处理视图Method[] declaredMethods = contollerBeanObj.getClass().getDeclaredMethods(); for(Method method:declaredMethods){ if(operate.equals(method.getName())){ //1.统一获取请求参数 //1.1获取当前方法的参数名称,返回参数数组 Parameter[] parameters = method.getParameters(); Object[] parameterValues = new Object[parameters.length];//保存参数的值 for(int i = 0; i < parameters.length; i++){ Parameter parameter = parameters[i]; String parameterName = parameter.getName(); if("req".equals(parameterName)){ parameterValues[i] = req; }else if("resp".equals(parameterName)){ parameterValues[i] = resp; }else if("session".equals(parameterName)){ parameterValues[i] = req.getSession(); }else{ //从请求中获取参数值 String parameterValue = req.getParameter(parameterName); String typeName = parameter.getType().getName(); Object parameterObj = parameterValue; //设置参数值的类型 if(parameterObj != null && "java.lang.Integer".equals(typeName)){ parameterObj = Integer.parseInt(parameterValue); } parameterValues[i] = parameterObj; } } //2,controller组件中的方法调用 method.setAccessible(true); Object returnObj = (String)method.invoke(contollerBeanObj, parameterValues); //3,视图处理 String methodReturnStr = (String) returnObj; if(methodReturnStr.startsWith("redirect:")){ //比如:redirect:fruit.do String redirectStr = methodReturnStr.substring("redirect:".length()); resp.sendRedirect(redirectStr); }else{//比如:edit index super.processTemplate(methodReturnStr,req,resp); } } }
5.2DispatcherServletException
异常类型
抛出发报机异常
5.3ViewBaseServlet
模板:用于设置渲染
5.3.1继承:HttpServlet
5.3.1设置web.xml配置文件:前缀和后缀
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext</param-value>
</context-param>
</web-app>
5.3.3重写init()
方法,初始化模板引擎
@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");//获取xml文件中对应的字符串
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);
}
5.3.4处理模板processTemplate()
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());
}
6.trans
6.1事务管理类TransactionManage
-
通过
ConnUtil
中的获取的Connection
进行设置 -
分别设置开启事务、提交事务、回滚事务
//开启事务 public static void beginTrans() throws SQLException { ConnUtil.getConnection().setAutoCommit(false); } //提交事务 public static void commit() throws SQLException { Connection conn = ConnUtil.getConnection(); conn.commit(); ConnUtil.closeConn(); } //回滚事务 public static void rollback() throws SQLException { Connection conn = ConnUtil.getConnection(); conn.rollback(); ConnUtil.closeConn(); }
7.util
工具包
7.1StringUtil
判断字符串是否为空
三.WEB类
1.页面index.html
-
渲染页面
<!-- 若列表为空,显示空页面 --> <tr th:if="${#lists.isEmpty(session.fruitList)}"> <td colspan="4">对不起!库存为空</td> </tr> <!-- 若列表有数据,遍历数据显示 --> <tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}"> <td><a th:text="${fruit.fname}" th:href="@{/fruit.do(fid=${fruit.fid},operate='edit')}">苹果</a></td> <td th:text="${fruit.price}">5</td> <td th:text="${fruit.fcount}">20</td> <!-- <td ><img src="imgs/del.jpg" class="delImg" th:οnclick="'delFruit(' + ${fruit.fid} + ')'"/></td> 拼接字符串方法--> <td ><img src="imgs/del.jpg" class="delImg" th:onclick="|delFruit(${fruit.fid})|"/></td> </tr>
-
查询表单
<form th:action="@{fruit.do}" method="post" style="float:left"> <input type="hidden" name="oper" value="search"/> 请输入查询关键字:<input type="text" name="keyword" th:value="${session.keyword}"/> <input type="submit" value="查询" class="btn"> </form>
-
编辑表单
<td><a th:text="${fruit.fname}" th:href="@{/fruit.do(fid=${fruit.fid},operate='edit')}">苹果</a></td>
-
添加表单: 跳转到
add.html
页面<a th:href="@{/add.html}" style="margin-bottomt: 4px; float:right">添加新库存记录</a>
-
页面跳转
<input type="button" value="首 页" class="btn" th:onclick="|page(1)|" th:disabled="${session.pageNo == 1}"/> <input type="button" value="上一页" class="btn" th:onclick="|page(${session.pageNo - 1})|" th:disabled="${session.pageNo == 1}"/> <input type="button" value="下一页" class="btn" th:onclick="|page(${session.pageNo + 1})|" th:disabled="${session.pageNo == session.pageCount}"/> <input type="button" value="尾 页" class="btn" th:onclick="|page(${session.pageCount})|" th:disabled="${session.pageNo == session.pageCount}"/>
2.页面eidt.html
-
渲染表单
-
提交表单
<form th:action="@{/fruit.do}" method="post" th:object="${fruit}"> <input type="hidden" name="operate" value="update"> <table id="tbl_fruit"> <!--隐藏域,不显示但发送表单--> <input type="hidden" name="fid" th:value="*{fid}"> <tr> <th class="w20">名称:</th> <td><input type="text" name="fname" th:value="*{fname}"></td> </tr> <tr> <th class="w20">单价:</th> <td><input type="text" name="price" th:value="*{price}"></td> </tr> <tr> <th class="w20">库存:</th> <td><input type="text" name="fcount" th:value="*{fcount}"></td> </tr> <tr> <th class="w20">备注:</th> <td><input type="text" name="remark" th:value="*{remark}"></td> </tr> <tr> <th class="w20" colspan="2"><input type="submit" value="修改"></th> </tr> </table> </form>
3.页面add.html
-
提交表单
<form action="fruit.do" method="post"> <input type="hidden" name="operate" value="add"> <table id="tbl_fruit"> <tr> <th class="w20">名称:</th> <td><input type="text" name="fname"></td> </tr> <tr> <th class="w20">单价:</th> <td><input type="text" name="price"></td> </tr> <tr> <th class="w20">库存:</th> <td><input type="text" name="fcount"></td> </tr> <tr> <th class="w20">备注:</th> <td><input type="text" name="remark"></td> </tr> <tr> <th class="w20" colspan="2"><input type="submit" value="添加"></th> </tr> </table> </form>
4.web.xml
文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext</param-value>
</context-param>
</web-app>
## 4.`web.xml`文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext</param-value>
</context-param>
</web-app>