一、MybatisPlus技术点
MyBatisPlus依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
1.MybatisPlus主键自增策略:
IdType的值如下: @TableId(value = "id",type = IdType.AUTO)
IdType的值 | 含义 |
---|---|
AUTO | 数据库自增 |
ID_WORKER | mp自带策略,19位的数字类型 |
ID_WORKER_STR | mp自带策略,19位的字符串类型 |
INPUT | 设置id值 |
NONE | 没有策略 |
UUID | 随机唯一值 |
分布式系统唯一ID生成方案汇总:https://cnblogs.com/haoxinyue/p/5208136.html
- UUID
- Redis生成Id
- MybatisPlus自带的ID_WORKER
- Twitter的snowflake算法
2.MybatisPlus自动填充
@TableField(fill=FieldFill.INSERT)
private Date createTime;
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date updateTime;
@Component
public class MyObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
3.MybatisPlus实现乐观锁
数据库新加version字段
实体类:
@Version
@TableField(fill=FieldFill.INSERT)
private Integer version;
MyObjectHandler类的insertFill方法里面加上:
this.setFieldValByName("version",1,metaObject);
配置类:
@MapperScan("com.wmyao.mpdemo.mapper")
@Configuration
public class MpConfig {
//乐观锁插件:报了参数没找到 Parameter 'MP_OPTLOCK_VERSION_ORIGINAL' not found. Available parameters are [param1, et],版本问题
// @Bean
// public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
// return new OptimisticLockerInnerInterceptor();
// }
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor optimisticLockerInnerInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
4.MybatisPlus配置控制台打印sql语句
1、配置文件为application.yml格式
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2、配置文件为application.properties格式
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
5.MybatisPlus 的简单查询和分页查询
分页查询需要添加配置类:
@Bean
//3.2或者以上版本
public PaginationInnerInterceptor paginationInnerInterceptor(){
return new PaginationInnerInterceptor();
}
@Bean
//3.1或者以下版本
public PaginationInterceptor paginationInnerInterceptor(){
return new PaginationInterceptor();
}
//分页查询
@Test
void testPage() {
//创建page对象,传入参数:当前页和每页显示记录数
//把分页所有数据封装到page对象里面,调用mp分页查询的方法
Page<User> page=new Page<>(1,3);
userMapper.selectPage(page,null);
//通过page对象获取分页数据
System.out.println(page.getCurrent());//当前页
System.out.println(page.getRecords());//每页数据list集合
System.out.println(page.getSize());//每页显示记录数
System.out.println(page.getTotal());//总记录数
System.out.println(page.getPages());//总页数
System.out.println(page.hasNext());//下一页
System.out.println(page.hasPrevious());//上一页
}
5.MybatisPlus 的物理删除和逻辑删除
MybatisPlus 的逻辑删除:数据依然存在,只修改标志位
实体类增加字段:
@TableLogic
private Integer deleted;//0默认 1已删除
配置application.properties 文件:该配置可选,默认0和1,可以修改成其他数值
# 全局逻辑删除字段
mybatis-plus.global-config.db-config.logic-delete-field=deleted
# 逻辑已删除值
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值
mybatis-plus.global-config.db-config.logic-not-delete-value=0
配置类中增加:MybatisPlus 3.1.1以下版本需要,以上不需要
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
测试逻辑删除:
@Test
void testDeleteById() {
//删除操作
int result=userMapper.deleteById(8L);
System.out.println("删除操作:"+result);
}
效果:
查询列表数据效果:MybatisPlus自动加上了deleted=0的条件判断
6.MybatisPlus 的SQL性能分析插件
在开发中可能会遇到慢sql的问题,MyBatisPlus提供了相关的性能分析插件,可设置SQL的超时时间。但是Mybatisplus3.2.0以上不支持本身的性能分析插件(PerformceInterceptor),支持p6spy组件,在此引入第三方的组件p6spy。
开发环境使用,线上不推荐
1.导入相应的依赖:
<!--p6spy-->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.6</version>
</dependency>
2.编写application.properties配置文件:注意修改数据库名、账号、密码
spring.datasource.driverClassName=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&charcterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
3.编写p6spy的核心配置文件spy.properties:
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 真实JDBC driver
driverlist=com.mysql.cj.jdbc.Driver
测试结果:
7.MybatisPlus 的条件构造器
类名 | 说明 |
---|---|
Wrapper | 条件构造抽象类,最顶端父类 |
AbstractWrapper | 用于查询条件封装,生成 sql 的 where 条件 |
QueryWrapper | Entity 对象封装操作类,不是用lambda语法 |
UpdateWrapper | Update 条件封装,用于Entity对象更新操作 |
AbstractLambdaWrapper | Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column |
LambdaQueryWrapper | 用于Lambda语法使用的查询Wrapper |
LambdaUpdateWrapper | Lambda 更新封装Wrapper |
AbstractWrapper的使用:
@Test
void testWrapper() {
// 1、ge、gt、le、lt、isNull、isNotNull
// =>UPDATE user SET deleted=1 WHERE deleted=0 AND name IS NULL AND age >= ? AND email IS NOT NULL
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.isNull("name").ge("age", 12).isNotNull("email");
// int result = userMapper.delete(queryWrapper);
// System.out.println("delete return count = " + result);
// 2、eq、ne:注意seletOne返回的是一条实体记录,当出现多条时会报错
// =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ?
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("name", "Tom");
// User user = userMapper.selectOne(queryWrapper);
// System.out.println(user);
// 3、between、notBetween:包含大小边界
// =>SELECT COUNT(1) FROM user WHERE deleted=0 AND age BETWEEN ? AND ?
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.between("age", 20, 30);
// Integer count = userMapper.selectCount(queryWrapper);
// System.out.println(count);
// 4、allEq =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ? AND id = ? AND age = ?
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// Map<String, Object> map = new HashMap<>();
// map.put("id", 2);
// map.put("name", "Jack");
// map.put("age", 20);
// queryWrapper.allEq(map);
// List<User> users = userMapper.selectList(queryWrapper);
// users.forEach(System.out::println);
// 5、like、notLike、likeLeft、likeRight:selectMaps返回Map集合列表
// =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ?
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper
// .notLike("name", "e")
// .likeRight("email", "t");
// List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
// maps.forEach(System.out::println);
// 6、in、notIn、inSql、notinSql、exists、notExists:
// in、notIn:
// notIn("age",{1,2,3})--->age not in (1,2,3)
// notIn("age", 1, 2, 3)--->age not in (1,2,3)
// inSql、notinSql:可以实现子查询
// 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
// 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
// =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND id IN (select id from user where id < 3)
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// //queryWrapper.in("id", 1, 2, 3);
// queryWrapper.inSql("id", "select id from user where id < 3");
// List<Object> objects = userMapper.selectObjs(queryWrapper);//返回值是Object列表
// objects.forEach(System.out::println);
// 7、or、and:注意这里使用的是 UpdateWrapper,不调用or则默认为使用 and 连
// =>UPDATE user SET name=?, age=?, update_time=? WHERE deleted=0 AND name LIKE ? OR age BETWEEN ? AND ?
// //修改值
// User use = new User();
// use.setAge(99);
// use.setName("Andy");
// //修改条件
// UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
// userUpdateWrapper
// .like("name", "h")
// .or()
// .between("age", 20, 30);
// int resul = userMapper.update(use, userUpdateWrapper);
// System.out.println(resul);
// 8、嵌套or、嵌套and:这里使用了lambda表达式,or中的表达式最后翻译成sql时会被加上圆括号
// =>UPDATE user SET name=?, age=?, update_time=? WHERE deleted=0 AND name LIKE ? OR ( name = ? AND age <> ? )
// //修改值
// User us = new User();
// us.setAge(99);
// us.setName("Andy");
// //修改条件
// UpdateWrapper<User> userUpdateWrappe = new UpdateWrapper<>();
// userUpdateWrappe
// .like("name", "h")
// .or(i -> i.eq("name", "李白").ne("age", 20));
// int re = userMapper.update(us, userUpdateWrappe);
// System.out.println(re);
// 9、orderBy、orderByDesc、orderByAsc
// =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 ORDER BY id DESC
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.orderByDesc("id");
// List<User> usersl = userMapper.selectList(queryWrapper);
// usersl.forEach(System.out::println);
// 10、last:直接拼接到 sql 的最后,注意只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用
// =>SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 limit 1
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.last("limit 1");
// List<User> u = userMapper.selectList(queryWrapper);
// u.forEach(System.out::println);
// 11、指定要查询的列=>SELECT id,name,age FROM user WHERE deleted=0
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.select("id", "name", "age");
// List<User> ul = userMapper.selectList(queryWrapper);
// ul.forEach(System.out::println);
// 12、set、setSql:最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中 的字段
// =>UPDATE user SET age=?, update_time=?, name=?, email = '123@qq.com' WHERE deleted=0 AND name LIKE ?
// //修改值
// User ur = new User();
// ur.setAge(99);
// //修改条件
// UpdateWrapper<User> userUpdate = new UpdateWrapper<>();
// userUpdateWrapper
// .like("name", "h")
// .set("name", "老李头")//除了可以查询还可以使用set设置修改的字段
// .setSql(" email = '123@qq.com'");//可以有子查询
// int res = userMapper.update(ur, userUpdate);
}
8.项目相关依赖
<java.version>1.8</java.version>
<guli.version>0.0.1-SNAPSHOT</guli.version>
<mybatis-plus.version>3.0.5</mybatis-plus.version>
<velocity.version>2.0</velocity.version>
<swagger.version>2.7.0</swagger.version>
<aliyun.oss.version>2.8.3</aliyun.oss.version>
<jodatime.version>2.10.1</jodatime.version>
<poi.version>3.17</poi.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-io.version>2.6</commons-io.version>
<httpclient.version>4.5.1</httpclient.version>
<jwt.version>0.7.0</jwt.version>
<aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
<aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
<aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
<aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
<aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
<fastjson.version>1.2.28</fastjson.version>
<gson.version>2.8.2</gson.version>
<json.version>20170516</json.version>
<commons-dbutils.version>1.7</commons-dbutils.version>
<canal.client.version>1.1.0</canal.client.version>
<docker.image.prefix>zx</docker.image.prefix>
<cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
二、前后端分离开发技术点
1.基本概念
2.代码生成器
基于MyBatisPlus环境,如果没有环境记得配置MyBatisPlus的依赖包
导入依赖包:
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
配置生成器:修改相关参数
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;
/**
* 代码生成器
*/
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");//当前项目的路径
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("wmyao");//作者名称
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略:数字ID_WORKER 字符串ID_WORKER_STR
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("edu"); //模块名
pc.setParent("com.wmyao");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("edu_teacher");//表名
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
//strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
控制台效果:
项目目录效果:红框部分都是代码生成器生成的
3.配置接口返回的json数据中的时间格式
时间格式显示问题:
解决格式显示问题:
配置时间格式
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
重启项目,访问接口,效果如下:
4.Swagger2整合
创建公共模块,在公共模块里面
导入依赖:<swagger.version>2.7.0</swagger.version>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>provided </scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<scope>provided </scope>
</dependency>
配置类:
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration//配置类
@EnableSwagger2 //swagger注解
public class SwaggerConfig {
@Bean
public Docket webApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/admin/.*")))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("网站-课程中心API文档")
.description("本文档描述了课程中心微服务接口定义")
.version("1.0")
.contact(new Contact("java", "http://atguigu.com", "1123@qq.com"))
.build();
}
}
注意:
在原来的项目启动类加上注解,保证可以扫描到公共模块的配置类:@ComponentScan(basePackages = {"com.wmyao"})
原来的项目依赖添加该公共模块:
<dependency>
<groupId>com.wmyao</groupId>
<artifactId>service_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
访问地址:
http://localhost:8001/swagger-ui.html
效果如下:
配置相关描述:
类描述:@Api(description = "讲师管理")
接口描述:@ApiOperation(value="所有讲师列表")
参数描述:@ApiParam(name="id",value="讲师id",required = true)
效果如图:
5.统一结果返回
创建一个interface ,定义返回码:
public interface ResultCode {
public static Integer SUCCESS = 20000; //成功
public static Integer ERROR = 20001; //失败
}
定义统一结果返回工具类:
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
//统一返回结果的类
@Data
public class R {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();
//把构造方法私有
private R() {}
//成功静态方法
public static R ok() {
R r = new R();
r.setSuccess(true);
r.setCode(ResultCode.SUCCESS);
r.setMessage("成功");
return r;
}
//失败静态方法
public static R error() {
R r = new R();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}
//return this;便于链式编程 R().code().(data)....
public R success(Boolean success){
this.setSuccess(success);
return this;
}
public R message(String message){
this.setMessage(message);
return this;
}
public R code(Integer code){
this.setCode(code);
return this;
}
public R data(String key, Object value){
this.data.put(key, value);
return this;
}
public R data(Map<String, Object> map){
this.setData(map);
return this;
}
}
测试使用:
@GetMapping("pageTeacher/{current}/{limit}")
public R pagelistteacher(@PathVariable long current,
@PathVariable long limit){
Page<EduTeacher> page = new Page<>(current, limit);
eduTeacherService.page(page,null);
long total=page.getTotal();//总记录数
List<EduTeacher> records = page.getRecords();//数据list集合
long pages = page.getPages();//总页数
// 第一种返回写法
// Map map = new HashMap<>();
// map.put("total",total);
// map.put("pages",pages);
// map.put("rows",records);
// return R.ok().data(map);
// 第二种返回写法
return R.ok().data("total",total).data("pages",pages).data("rows",records);
}
6.条件查询分页
新增vo类,定义条件类型:
@Data
public class TeacherQuery {
@ApiModelProperty(value = "教师名称,模糊查询")
private String name;
@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
private Integer level;
@ApiModelProperty(value = "查询开始时间", example = "2019-01-01 10:10:10")
private String begin;//注意,这里使用的是String类型,前端传过来的数据无需进行类型转换
@ApiModelProperty(value = "查询结束时间", example = "2019-12-01 10:10:10")
private String end;
}
测试使用:@RequestBody
注解需要用 @PostMapping
//条件查询带分页的方法
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable long current,
@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery) {
//创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current,limit);
//构建条件
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
// 多条件组合查询
// mybatis学过 动态sql
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
//判断条件值是否为空,如果不为空拼接条件
if(!StringUtils.isEmpty(name)) {
//构建条件
wrapper.like("name",name);
}
if(!StringUtils.isEmpty(level)) {
wrapper.eq("level",level);
}
if(!StringUtils.isEmpty(begin)) {
wrapper.ge("gmt_create",begin);
}
if(!StringUtils.isEmpty(end)) {
wrapper.le("gmt_create",end);
}
//调用方法实现条件查询分页
eduTeacherService.page(pageTeacher,wrapper);
long total = pageTeacher.getTotal();//总记录数
List<EduTeacher> records = pageTeacher.getRecords(); //数据list集合
return R.ok().data("total",total).data("rows",records);
}
7.统一异常处理
指定异常处理的注解:@ExceptionHandler
import com.wmyao.commonutils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
//指定出现什么异常执行这个方法
@ExceptionHandler(Exception.class)
@ResponseBody //为了返回数据
public R error(Exception e) {
e.printStackTrace();
return R.error().message("执行了全局异常处理.."+e.getMessage());
}
//特定异常
@ExceptionHandler(ArithmeticException.class)
@ResponseBody //为了返回数据
public R error(ArithmeticException e) {
e.printStackTrace();
return R.error().message("执行了ArithmeticException异常处理..");
}
//自定义异常
@ExceptionHandler(GuliException.class)
@ResponseBody //为了返回数据
public R error(GuliException e) {
log.error(e.getMessage());
e.printStackTrace();
return R.error().code(e.getCode()).message(e.getMsg());
}
自定义异常类:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor //生成有参数构造方法
@NoArgsConstructor //生成无参数构造
public class GuliException extends RuntimeException {
private Integer code;//状态码
private String msg;//异常信息
}
调用:
try {
int i = 10/0;
}catch(Exception e) {
//执行自定义异常
throw new GuliException(20001,"执行了自定义异常处理....");
}
8.统一日志处理
看到的信息从少到多顺序如下:debug最多
#设置日志级别
logging.level.root=debug
logback日志插件:
1.注释掉其他的日志配置
#mybatis日志
#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
##设置日志级别
#logging.level.root=debug
2.resource中创建logback-spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="D:/guli_1010/edu" />
<!-- 彩色日志 -->
<!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
如果未设置此属性,那么当前logger将会继承上级的级别。
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!--可以输出项目中的debug日志,包括mybatis的sql日志-->
<logger name="com.guli" level="INFO" />
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>
<!--生产环境:输出到文件-->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>
</configuration>
9.跨域问题
解决:@CrossOrigin //解决跨域
10.vue路由切换监听
watch: { //监听
$route(to, from) { //路由变化方式,路由发生变化,方法就会执行
this.init()
}
},
methods:{
init() {
//判断路径有id值,做修改
if(this.$route.params && this.$route.params.id) {
//从路径获取id值
const id = this.$route.params.id
//调用根据id查询的方法
this.getInfo(id)
} else { //路径没有id值,做添加
//清空表单
this.teacher = {}
}
}
11.数组转字符串/字符串转数组
1.字符串转数组
使用Java split() 方法
split() 方法根据匹配给定的正则表达式来拆分字符串。
注意: . 、 | 和 * 等转义字符,必须得加 \。多个分隔符,可以用 | 作为连字符。
// 字符串转数组 java.lang.String
String str = "0,1,2,3,4,5";
String[] arr = str.split(","); // 用,分割
System.out.println(Arrays.toString(arr)); // [0, 1, 2, 3, 4, 5]
2.数组转字符串
方法一: 遍历
String[] arr = { "0", "1", "2", "3", "4", "5" };
// 遍历
StringBuffer str5 = new StringBuffer();
for (String s : arr) {
str5.append(s);
}
System.out.println(str5.toString()); // 012345
方法二: 使用StringUtils的join方法
//数组转字符串 org.apache.commons.lang3.StringUtils
String str3 = StringUtils.join(arr); // 数组转字符串,其实使用的也是遍历
System.out.println(str3); // 012345
String str4 = StringUtils.join(arr, ","); // 数组转字符串(逗号分隔)(推荐)
System.out.println(str4); // 0,1,2,3,4,5
依赖引入:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
方法三: 使用ArrayUtils的toString方法
// 数组转字符串 org.apache.commons.lang3.ArrayUtils
String str2 = ArrayUtils.toString(arr, ","); // 数组转字符串(逗号分隔,首尾加大括号)
System.out.println(str2); // {0,1,2,3,4,5}
12.解决映射文件xml找不到的问题
报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
最直接的解决办法:将xml文件放到resource目录下即可
一般开发中常用方法如下:
方法一,pom文件配置:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml </include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
方法二,application.properties配置:
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/wmyao/edu/mapper/xml/*.xml
13.正则表达式
W3Cschool:https://www.w3cschool.cn/regexp/x9hf1pq9.html
三、前端技术点
1.前端介绍
1.vscode的插件安装:
2.vscode工作区创建
3. vscode运行项目:会在默认浏览器中访问http://127.0.0.1:5500/demo/1.html
2.前端技术es6
1.es6介绍
官方网站:http://es6.ruanyifeng.com/
2.es6语法
//1.es6如何定义变量
// var 声明的变量没有局部作用域
// let 声明的变量 有局部作用域
// js定义:var a = 1;
// es6写法定义变量,使用关键字 let let a = 10;
//创建代码块,定义变量
{
var a = 10
let b = 20
}
//在代码块 外面输出
console.log(a)
console.log(b) //Uncaught ReferenceError: b is not defined
//2.定义变量特点:let定义变量有作用范围,不能重复定义
var a = 1
var a = 2
let m = 10
let m = 20 //Uncaught SyntaxError: Identifier 'm' has already been declared
console.log(a)
console.log(m)
//3.定义常量
const PI = "3.1415"
//常量值一旦定义,不能改变
//PI = 3 //Uncaught TypeError: Assignment to constant variable.
//定义常量必须初始化
const AA //Uncaught SyntaxError: Missing initializer in const declaration
//4.es6数组结构
//传统写法
let a=1,b=2,c=3
console.log(a, b, c)
//es6写法
let [x,y,z] = [10,20,30]
console.log(x, y, z)
//5.对象结构
//定义对象
let user = {"name":"lucy","age":20}
//传统从对象里面获取值
let name1 = user.name
let age1 = user.age
console.log(name1+"=="+age1)
//es6获取对象值
let {name,age} = user
console.log(name+"**"+age)
//6.模本字符串
//1 使用`符号实现换行
let str1 = `hello,
es6 demo up!`
//console.log(str1)
//2 在`符号里面使用表达式获取变量值
let name = "Mike"
let age = 20
let str2 = `hello,${name},age is ${age+1}`
//console.log(str2)
//3 在`符号调用方法
function f1() {
return "hello f1"
}
let str3 = `demo, ${f1()}`
console.log(str3)
//7.声明对象
const age = 12
const name = "lucy"
//传统方式定义对象
const p1 = {name:name,age:age}
// console.log(p1)
//es6定义变量
const p2 = {name,age}
console.log(p2)
//8.定义方法简写方式
//传统方式定义的方法
const person1 = {
sayHi:function(){
console.log("Hi")
}
}
//调用
person1.sayHi()
//es6
const person2 = {
sayHi(){
console.log("Hi")
}
}
//9.对象拓展运算符
//1 对象复制
let person1 = {"name":"lucy","age":20}
let person2 = {...person1}
//console.log(person2) //Uncaught SyntaxError: Unexpected token ...浏览器版本兼容问题
//2 对象合并
let name = {name:'mary'}
let age = {age:30}
let p2 = {...name,...age}
console.log(p2)
//10.箭头函数
//1 传统方式创建方法
//参数 => 函数体
var f1 = function(m) {
return m
}
//console.log(f1(2))
//使用箭头函数改造
var f2 = m => m
// console.log(f2(8))
//2 复杂一点方法
var f3 = function(a,b) {
return a+b
}
//console.log(f3(1,2))
//箭头函数简化
var f4 = (a,b) => a+b
console.log(f4(2,2))
3.前端技术vue.js
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
官方网站:https://cn.vuejs.org
<!-- id标识vue作用的范围 -->
<div id="app">
<!-- {{}} 插值表达式,绑定vue中的data数据 -->
{{ message }}
</div>
<script src="vue.min.js"></script>
<script>
// 创建一个vue对象
new Vue({
el: '#app',//绑定vue作用的范围
data: {//定义页面中显示的模型数据
message: 'Hello Vue!'
}
})
</script>
这就是声明式渲染:Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。
这里的核心思想就是没有繁琐的DOM操作,例如jQuery中,我们需要先找到div节点,获取到DOM对象,然后进行一系列的节点操作。
1.生成代码片段
{
"vue htm": {
"scope": "html",
"prefix": "vuehtml",
"body": [
"<!DOCTYPE html>",
"<html lang=\"en\">",
"",
"<head>",
" <meta charset=\"UTF-8\">",
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
" <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">",
" <title>Document</title>",
"</head>",
"",
"<body>",
" <div id=\"app\">",
"",
" </div>",
" <script src=\"vue.min.js\"></script>",
" <script>",
" new Vue({",
" el: '#app',",
" data: {",
" $1",
" }",
" })",
" </script>",
"</body>",
"",
"</html>",
],
"description": "my vue template in html"
}
}
2.v-bind 单向数据绑定
body标签里的代码:
<div id="app">
<!-- v-bind指令
单向数据绑定
这个指令一般用在标签属性里面,获取值
-->
<h1 v-bind:title="message">
{{content}}
</h1>
<!--简写方式-->
<h2 :title="message">
{{content}}
</h2>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
content: '我是标题',
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
3.v-model 双向数据绑定
body标签里的代码:
<div id="app">
<input type="text" v-bind:value="searchMap.keyWord"/>
<!--双向绑定-->
<input type="text" v-model="searchMap.keyWord"/>
<p>{{searchMap.keyWord}}</p>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
searchMap:{
keyWord: '尚硅谷'
}
}
})
</script>
4.vue 事件绑定
body标签里的代码:
<div id="app">
<!--vue绑定事件-->
<button v-on:click="search()">查询</button>
<!--vue绑定事件简写,search方法后面括号可以不写-->
<button @click="search()">查询1</button>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
searchMap:{
keyWord: '尚硅谷'
},
//查询结果
result: {}
},
methods:{//定义多个方法
search() {
console.log('search....')
},
f1() {
console.log('f1...')
}
}
})
</script>
5.vue修饰符
submit.prevent阻止表单自带的提交,提交到自定义的方法:onSubmit
body标签里的代码:
<div id="app">
<form action="save" v-on:submit.prevent="onSubmit">
<input type="text" id="name" v-model="user.username"/>
<button type="submit">保存</button>
</form>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
user:{}
},
methods:{
onSubmit() {
if (this.user.username) {
console.log('提交表单')
} else {
alert('请输入用户名')
}
}
}
})
</script>
6.vue指令v-if
body标签里的代码:
<div id="app">
<input type="checkbox" v-model="ok"/>是否同意
<!--条件指令 v-if v-else -->
<h1 v-if="ok">尚硅谷</h1>
<h1 v-else>谷粒学院</h1>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
ok:false
}
})
</script>
与v-show的比较:
7.vue指令v-for
body标签里的代码:
<div id="app">
<ul>
<li v-for="n in 10"> {{n}} </li>
</ul>
<ol>
<li v-for="(n,index) in 10">{{n}} -- {{index}}</li>
</ol>
<hr/>
<table border="1">
<tr v-for="user in userList">
<td>{{user.id}}</td>
<td>{{user.username}}</td>
<td>{{user.age}}</td>
</tr>
</table>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
userList: [
{ id: 1, username: 'helen', age: 18 },
{ id: 2, username: 'peter', age: 28 },
{ id: 3, username: 'andy', age: 38 }
]
}
})
</script>
8.vue组件
body标签里的代码:
<div id="app">
<Navbar></Navbar>
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
//定义vue使用的组件
components: {
//组件的名字
'Navbar': {
//组件的内容
template: '<ul><li>首页</li><li>学员管理</li></ul>'
}
}
})
</script>
9.vue全局组件
body标签里的代码:
<div id="app">
<Navbar></Navbar>
</div>
<script src="vue.min.js"></script>
<script src="components/Navbar.js"></script>
<script>
new Vue({
el: '#app',
data: {
}
})
</script>
全局组件Navbar.js内容:
// 定义全局组件
Vue.component('Navbar', {
template: '<ul><li>首页</li><li>学员管理</li><li>讲师管理</li></ul>'
})
10.vue生命周期
body标签里的代码:
<div id="app">
hello
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
},
created() {
debugger
//在页面渲染之前执行
console.log('created....')
},
mounted() {
debugger
//在页面渲染之后执行
console.log('mounted....')
}
})
</script>
11.vue路由
引入vue-router.min.js
body标签里的代码:
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/">首页</router-link>
<router-link to="/student">会员管理</router-link>
<router-link to="/teacher">讲师管理</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
//引入顺序固定如下:
<script src="vue.min.js"></script>
<script src="vue-router.min.js"></script>
<script>
// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Welcome = { template: '<div>欢迎</div>' }
const Student = { template: '<div>student list</div>' }
const Teacher = { template: '<div>teacher list</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。
const routes = [
{ path: '/', redirect: '/welcome' }, //设置默认指向的路径
{ path: '/welcome', component: Welcome },
{ path: '/student', component: Student },
{ path: '/teacher', component: Teacher }
]
// 3. 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 从而让整个应用都有路由功能
const app = new Vue({
el: '#app',
router
})
</script>
4.前端技术axious
axious在vue中发送ajax请求
axious的使用,引入axious.min.js
:
html的body部分:
<div id="app">
<!--把userList数组里面数据显示 使用v-for指令 -->
<div v-for="user in userList">
{{user.name}} -- {{user.age}}
</div>
</div>
<script src="vue.min.js"></script>
<script src="axios.min.js"></script>
<script>
new Vue({
el: '#app',
//固定的结构
data: { //在data定义变量和初始值
//定义变量,值空数组
userList:[]
},
created() { //页面渲染之前执行
//调用定义的方法
this.getUserList()
},
methods:{//编写具体的方法
//创建方法 查询所有用户数据
getUserList() {
//使用axios发送ajax请求
//axios.提交方式("请求接口路径").then(箭头函数).catch(箭头函数)
axios.get("data.json")
.then(response =>{//请求成功执行then方法
//response就是请求之后返回数据
//console.log(response)
//通过response获取具体数据,赋值给定义空数组
this.userList = response.data.data.items
console.log(this.userList)
})
.catch(error =>{
}) //请求失败执行catch方法
}
}
})
</script>
data.json:
{
"sucess":true,
"code":20000,
"message":"成功",
"data":{
"items":[
{"name":"lucy","age":20},
{"name":"mary","age":30},
{"name":"jack","age":40}
]
}
}
5.前端技术element-ui
官方网站:https://element.eleme.cn/#/zh-CN
1.vue-element-admin
1、简介
vue-element-admin是基于element-ui 的一套后台管理系统集成方案。
功能:https://panjiachen.github.io/vue-element-admin-site/zh/guide/#功能
GitHub地址:https://github.com/PanJiaChen/vue-element-admin
项目在线预览:https://panjiachen.gitee.io/vue-element-admin
2、安装:
# 解压压缩包
# 进入目录
cd vue-element-admin-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/
npm run dev
2.vue-admin-template
1、简介
vueAdmin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。
GitHub地址:https://github.com/PanJiaChen/vue-admin-template
建议:你可以在 vue-admin-template 的基础上进行二次开发,把 vue-element-admin当做工具箱,想要什么功能或者组件就去 vue-element-admin 那里复制过来。
2、安装
# 解压压缩包
# 进入目录
cd vue-admin-template-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9528/
npm run dev
6.前端技术nodejs
nodejs的介绍和安装:
安装后检验版本:node -v
执行js脚本命令:node 01.js
// 作为服务器启动,类似tomcat,端口号为8888
const http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
response.end('Hello Server');
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
启动该js,浏览器访问:http://127.0.0.1:8888/
,效果如下:
NPM:
安裝nodejs时自动安装,可直接检验版本:npm -v
初始化命令:npm init -y
修改npm镜像:
NPM官方的管理的包都是从 http://npmjs.com下载的,但是这个网站在国内速度很慢。
这里推荐使用淘宝 NPM 镜像 http://npm.taobao.org/ ,淘宝 NPM 镜像是一个完整 npmjs.com 镜像,同步频率目前为 10分钟一次,以保证尽量与官方服务同步。
设置镜像地址:
#经过下面的配置,以后所有的 npm install 都会经过淘宝的镜像地址下载
npm config set registry https://registry.npm.taobao.org
#查看npm配置信息
npm config list
npm install命令的使用
#使用 npm install 安装依赖包的最新版,
#模块安装的位置:项目目录\node_modules
#安装会自动在项目目录下添加 package-lock.json文件,这个文件帮助锁定安装包的版本
#同时package.json 文件中,依赖包会被添加到dependencies节点下,类似maven中的 <dependencies>
npm install jquery
#npm管理的项目在备份和传输的时候一般不携带node_modules文件夹
npm install #根据package.json中的配置下载依赖,初始化项目
#如果安装时想指定特定的版本
npm install jquery@2.1.x
#devDependencies节点:开发时的依赖包,项目打包到生产环境的时候不包含的依赖
#使用 -D参数将依赖添加到devDependencies节点
npm install --save-dev eslint
#或
npm install -D eslint
#全局安装
#Node.js全局安装的npm包和工具的位置:用户目录\AppData\Roaming\npm\node_modules
#一些命令行工具常使用全局安装的方式
npm install -g webpack
其它命令
#更新包(更新到最新版本)
npm update 包名
#全局更新
npm update -g 包名
#卸载包
npm uninstall 包名
#全局卸载
npm uninstall -g 包名
7.前端技术babel转码器
Babel提供babel-cli工具,用于命令行转码。它的安装命令如下:
npm install --global babel-cli
#查看是否安装成功
babel --version
创建es6规范的js文件:
// 转码前
// 定义数据
let input = [1, 2, 3]
// 将数组的每个元素 +1
input = input.map(item => item + 1)
console.log(input)
配置.babelrc文件:
{
"presets": ["es2015"],
"plugins": []
}
安装转码器:npm install --save-dev babel-preset-es2015
转码:
# 转码结果写入一个文件
mkdir dist1
# --out-file 或 -o 参数指定输出文件
babel src/example.js --out-file dist1/compiled.js
# 或者
babel src/example.js -o dist1/compiled.js
# 整个目录转码
mkdir dist2
# --out-dir 或 -d 参数指定输出目录
babel src --out-dir dist2
# 或者
babel src -d dist2
9.前端技术模块化
es5实现模块化操作:
es6实现模块化操作:
10.前端技术webpack
初始化项目
全局安装:npm install -g webpack webpack-cli
查看版本号:webpack -v
初始化项目:npm init -y
创建common.js:
exports.info = function (str) {
document.write(str);
}
创建utils.js:
exports.add = function (a, b) {
return a + b;
创建main.js:
const common = require('./common');
const utils = require('./utils');
common.info('Hello world!' + utils.add(100, 200));
JS打包
1、创建配置文件webpack.config.js:
const path = require("path"); //Node.js内置模块
module.exports = {
entry: './src/main.js', //配置入口文件
output: {
path: path.resolve(__dirname, './dist'), //输出路径,__dirname:当前文件所在路径
filename: 'bundle.js' //输出文件
}
}
2、命令行执行编译命令:
webpack #有黄色警告
webpack --mode=development #没有警告
#执行后查看bundle.js 里面包含了上面两个js文件的内容并惊醒了代码压缩
也可以配置项目的npm运行命令,修改package.json文件
"scripts": {
//...,
"dev": "webpack --mode=development"
}
3、运行npm命令执行打包:npm run dev
4、创建index.html:引用bundle.js
<body>
<script src="dist/bundle.js"></script>
</body>
css打包:
1、安装style-loader和 css-loader
Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。
Loader 可以理解为是模块和资源的转换器。
首先我们需要安装相关Loader插件,css-loader 是将 css 装载到 javascript;style-loader 是让 javascript 认识cssnpm install --save-dev style-loader css-loader
2、修改webpack.config.js
const path = require("path"); //Node.js内置模块
module.exports = {
}
const path = require("path"); //Node.js内置模块
module.exports = {
//js打包配置
entry: './src/main.js', //配置入口文件
output: {
path: path.resolve(__dirname, './dist'), //输出路径,__dirname:当前文件所在路径
filename: 'bundle.js' //输出文件
}
//css打包
module: {
rules: [
{
test: /\.css$/, //打包规则应用到以css结尾的文件上
use: ['style-loader', 'css-loader']
}
]
}
}
3、在src文件夹创建style.css
body{
background:pink;
}
4、修改main.js
在第一行引入style.css
require('./style.css');
5、浏览器中查看index.html
11.前端页面环境和框架结构
运行vue-admin-template-master前端框架
1.导入该模板项目
2.安装配置文件的依赖:npm install
3.运行项目:npm run dev
,出现问题:
Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime
解决:node sass不支持当前环境,所以可以直接删掉原来不支持本机的node sass,再重新安装就行了
删除:npm uninstall --save node-sass
安装:npm install --save node-sass
4.启动成功的效果:
浏览器访问效果: