【JavaWeb】实训的长篇笔记(上)(1)https://developer.aliyun.com/article/1407210
4、数据库设计
回头再改表结构是非常麻烦的。
三大范式:1NF(列的原子性),2NF(直接依赖,即所有其他属性都直接依赖于主键),3NF(每个字段不能传递依赖于主键,如有aid列,就不要address列了)。
原则:数据库的性能,比规范化重要。
数据库设计的过程:
- 找出实体(对象)
- 找出实体的属性
- 找出实体之间的关系 (E-R实体关系图)
- 将ER图转换为表
找实体:
用户实体 users:主键 uid,密码 password,头像 photo,昵称 nickname,真实姓名 name,性别 sex,职业 career,宣言 words,
审核状态 chechstatus(待审核1 通过2 未通过3) ,
账号状态 accstatus(正常1 禁用2)
首页推荐 indexstatus(未推荐1 已推荐2)
广告实体 ad:主键 adid,图片 image,说明
朋友实体 friends:主键 fid,邀请方 send,被邀请方 accept,邀请状态 status(未处理1 通过2 拒绝3)
职业表 carrer:主键 cid,名称 cname
英文命名尽量通俗,去查的单词可能后来自己都不认识了。
5、数据库实现
表的Comments在哪里体现?
为什么要单独创建一个职业表?
- 头像:用字符串存放路径
六、连接数据库:JDBC
Web项目的三大块:前台,后台,数据库。
JDBC:Java DataBase Connectivity
1、使用流程
实现步骤:
- 导入驱动jar包。数据库厂商给java提供了连接db的实现类。java只提供接口,实际调用的数据库厂商的实现。即java的同一套接口可以连接不同的数据库。
jar包放到 /lib 目录下
Add to Build Path,产生一个Referenced Libraries。
2.注册驱动。
记得注册时区
localhost | 127.0.0.1
有多个异常:使用父类Exception捕获所有的异常。
3.创建连接。
desc users 可以查看表的属性。
4.创建业务sql。
5.创建传送和执行sql的对象。PrepareStatement
修改操作,得到的是影响行数。
查询操作,得到的是一张表。返回List,遍历即可。
6.执行sql,根据结果处理业务逻辑。
从语句的影响行数来判断是否成功执行
7.关闭资源。
在一行数据中取属性。
使用各种get方法,一个个地取出属性。
然后将这些属性构成一个对象。
javabean:能够存储数据的一些类。(那记录呢?)
自动生成get和set方法、构造方法。
source --> Generate Getters and Setters
标准的javabean:又脚vo(值对象),dto(数据传输对象),model(数据类型)
- 唯一作用:进行数据存储(封装)和传输。
// ResultSet对象的使用示例 while(rs.next()) { String id = rs.getString(1); int sex = rs.getInt("sex"); System.out.println(id); }
重载:一件事情,根据不同的条件有不同的实现方式。
对比:突然感觉,python中的字典就很方便。
局部类型推断 var:在java10版本后。
感想:好像,自己写代码的时间就过得特别快。
2、参数处理
- sql注入。可以干嘛?
- sql的执行计划?
- 防御:sql语句使用占位符参数,查询时再给参数赋值,会自动进行类型转换(内部有很多处理),丢掉多余的部分。
将sex值只作为sex的字段值进行设置,而不是组合sql语句。 - 组合模糊查询:
nm+"%"
// _sex = "1 or 1=1" // 可以被sql注入的语句 String sql = "select * from users where sex = " + _sex + ";"; PreparedStatement pstmt = conn.prepareStatement(sql); // 防sql注入的语句 String sql = "select * from users where sex = ?;"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, _sex); select * from users where sex = '1 or 1=1';
问题:pstmt.setString()
是将_sex
作为一个字符串加入sql语句的,它为什么可以正常执行呢?在什么阶段进行了处理?
答:你会发现下面这条语句就是可以正常执行(即使sex的类型为int)。
select * from users where sex = '1 or 1=1';
3、简单封装
- 一共只需要一个,也只需要建立一次数据库连接。
- 开发角度的封装。
- 抽取connection对象的创建。
public static Connection getConn()
- 抽取资源的关闭。
public static void close(Connection conn, PreparedStatement pstmt)
- 单例模式?
- 静态块:只在类加载时执行一次。
- finally关键字:不管catch执不执行,里面都会执行。
- 条件判断将null写在前面(老手):
null != pstmt
;理论上可以避免空值异常。
感受:在jdbcUtil类中,多层嵌套的try-catch-finally
看起来好丑。
七、MVC系统架构
1、架构介绍
不管java如何,先看生活中如何。
顾客:前端
静态技术:html,css,js,bs
动态技术:jsp,vue --> 静态数据动态化
下单:发送请求
服务员(控制层):控制整个业务流程走向,向前端负责。
接受前端请求,并将请求获取到的数据响应前端。
技术:jsp,Servet,SpringMVC,SpringBoot
厨师(服务层):向控制层负责,为控制层提供服务。
能够提供各种方法,处理控制层的业务。
思想:面向接口编程。接口定义功能,实现类实现功能。控制层只需要调用接口方法即可,而无需知道具体实现。
配菜师(DAO层):数据访问层,从数据库中获取数据交给服务层,为服务层服务。
只负责数据处理,将数据处理的结构反馈给服务层即可。也面向接口编程。
数据库连接技术:JDBC,MyBatis
菜(DB数据库):存放数据。
MySQL,ORACLE,DB2
MVC:Model(数据模型),View(视图),Controller(控制)
流程:View --> Controller --> Services --> DAO --> DB
2、系统架构搭建
- src - edu.ft.control - edu.ft.services - edu.ft.dao - edu.ft.util - edu.ft.bean - WebContent
层次展示包结构:Package Presentation --> Hierarchical
想法:总是只看功能,不关心如何实现,真的好吗?
理解mvc代码执行流程:(以模拟注册为例)
control:把注册信息入库,得到入库的结果,将结果告知用户。
service:给控制器提供一个能够入库的功能
- dao:给服务层提供一个能够插入数据库的功能。存粹地处理数据,而不进行任何业务逻辑的处理。
- control - Test - services - impl :实现类 - IUsersServiceImpl - IUsersService :一个接口 - dao - impl - IUsersDaoImpl - IUsersDao
- 使用对象传数据,避免冗长的参数列表。
问题:注解Override是什么?
问题:给类再包一层接口,不会显得多余吗?
3、小结
- 需求分析:要做什么。
- 概要设计:做成什么样子。
- 详细设计:每一个细节怎么做。
各个步骤可以并行开始,而不是只能一条龙。
- 执行计划:解析sql
4、Web项目运行部署
要实现静态数据的动态化。
服务器:运行项目的一个容器,其实就是一个软件,如tomcat。汽车要放到马路环境,才能启动运行。
在Eclipse中配置tomcat:windows --> Preferences --> Server --> Runtime Environments
给项目配置tomcat:右键项目 --> Propenties for … --> Java Build Path --> Libraries
运行项目(部署到tomcat中):Window --> show view --> 搜索Servers --> open
默认端口号为8080
访问项目:url:http://IP(localhost):端口号/项目资源 ,例如http://localhost:8080/friends/index.html