在线教育项目技术笔记1

一、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_WORKERmp自带策略,19位的数字类型
ID_WORKER_STRmp自带策略,19位的字符串类型
INPUT设置id值
NONE没有策略
UUID随机唯一值

分布式系统唯一ID生成方案汇总https://cnblogs.com/haoxinyue/p/5208136.html

  1. UUID
  2. Redis生成Id
  3. MybatisPlus自带的ID_WORKER
  4. 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 条件
QueryWrapperEntity 对象封装操作类,不是用lambda语法
UpdateWrapperUpdate 条件封装,用于Entity对象更新操作
AbstractLambdaWrapperLambda 语法使用 Wrapper统一处理解析 lambda 获取 column
LambdaQueryWrapper用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapperLambda 更新封装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.启动成功的效果:
在这里插入图片描述
浏览器访问效果:
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值