011 springboot整合mybatis-plus 首页加载热商品food评分前8的食物

ConfigRegistCenter.java


package com.example.config;

import com.example.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration //将当前类注入到Spring容器中
@EnableWebMvc
public class ConfigRegistCenter implements WebMvcConfigurer {
    //注册拦截器

    public void addInterceptors(InterceptorRegistry registry){

        // "/" 项目根目录(http://localhost:80/app)

        registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**") //所有资源,包括静态资源
                .excludePathPatterns("/static/**")
                .excludePathPatterns("/customer/login")
                .excludePathPatterns("/food/hot")
                .excludePathPatterns("/error");

    }



    // 静态资源配置
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/","classpath:webapp/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }



}


MybatisplusConfig.java


package com.example.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //当前是类配置类 @Component
public class MybatisplusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true);

        interceptor.addInnerInterceptor(paginationInnerInterceptor);


        return interceptor;
    }

}




RedisConfig.java


package com.example.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 配置redistemplate序列化
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    //过期时间-1天
    private Duration timeToLive = Duration.ofDays(-1);

    /**
     * RedisTemplate 先关配置
     *
     * @param factory
     * @return
     */
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        //LocalDatetime序列化
        JavaTimeModule timeModule = new JavaTimeModule();
        timeModule.addDeserializer(LocalDate.class,
                new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        timeModule.addDeserializer(LocalDateTime.class,
                new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        timeModule.addSerializer(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        timeModule.addSerializer(LocalDateTime.class,
                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.registerModule(timeModule);

        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }


    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        //默认1
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                .disableCachingNullValues();
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
        return redisCacheManager;
    }

    @Bean
    RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
        listenerContainer.setConnectionFactory(connectionFactory);
        return listenerContainer;
    }


    /**
     * key 类型
     * @return
     */
    private RedisSerializer<String> keySerializer() {
        return  new StringRedisSerializer();
    }

    /**
     * 值采用JSON序列化
     * @return
     */
    private RedisSerializer<Object> valueSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }

}





FoodController.java


package com.example.controller;


import com.example.entity.Food;
import com.example.service.IFoodService;
import com.example.util.ServerResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author dd
 * @since 2024-04-20
 */
@RestController
@RequestMapping("/food")
public class FoodController {
    @Autowired
    private IFoodService foodService;


    @GetMapping("hot")
    public ServerResult getHotProducts(HttpServletRequest request){
        List<Food> list = foodService.getHotFood();
        if(list != null && list.size()>0){
            ServerResult result = ServerResult.getSuccess(list);
            return result;
        }
        //list.get(0).getFoodMainImg();
        return ServerResult.getFail(null);
    }


}





Food.java


package com.example.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * <p>
 * 
 * </p>
 *
 * @author dd
 * @since 2024-04-20
 */
public class Food implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 美食id
     */
    @TableId(value = "food_id", type = IdType.AUTO)
    private Integer foodId;

    /**
     * 美食名
     */
    private String foodName;

    /**
     * 美食价格
     */
    private BigDecimal foodPrice;

    /**
     * 美食评分
     */
    private Float foodScore;

    /**
     * 美食详情
     */
    private String foodDetail;

    /**
     * 美食类型
     */
    private String foodType;

    /**
     * 美食图片
     */
    private String foodMainImg;

    /**
     * 美食推荐状态
     */
    private Integer foodRecommendStatus;

    /**
     * 创建时间
     */
    private LocalDateTime foodCteateTime;

    /**
     * 更新时间
     */
    private LocalDateTime foodUpdateTime;

    private String other1;

    private String other2;

    public Integer getFoodId() {
        return foodId;
    }

    public void setFoodId(Integer foodId) {
        this.foodId = foodId;
    }
    public String getFoodName() {
        return foodName;
    }

    public void setFoodName(String foodName) {
        this.foodName = foodName;
    }
    public BigDecimal getFoodPrice() {
        return foodPrice;
    }

    public void setFoodPrice(BigDecimal foodPrice) {
        this.foodPrice = foodPrice;
    }
    public Float getFoodScore() {
        return foodScore;
    }

    public void setFoodScore(Float foodScore) {
        this.foodScore = foodScore;
    }
    public String getFoodDetail() {
        return foodDetail;
    }

    public void setFoodDetail(String foodDetail) {
        this.foodDetail = foodDetail;
    }
    public String getFoodType() {
        return foodType;
    }

    public void setFoodType(String foodType) {
        this.foodType = foodType;
    }
    public String getFoodMainImg() {
        return foodMainImg;
    }

    public void setFoodMainImg(String foodMainImg) {
        this.foodMainImg = foodMainImg;
    }
    public Integer getFoodRecommendStatus() {
        return foodRecommendStatus;
    }

    public void setFoodRecommendStatus(Integer foodRecommendStatus) {
        this.foodRecommendStatus = foodRecommendStatus;
    }
    public LocalDateTime getFoodCteateTime() {
        return foodCteateTime;
    }

    public void setFoodCteateTime(LocalDateTime foodCteateTime) {
        this.foodCteateTime = foodCteateTime;
    }
    public LocalDateTime getFoodUpdateTime() {
        return foodUpdateTime;
    }

    public void setFoodUpdateTime(LocalDateTime foodUpdateTime) {
        this.foodUpdateTime = foodUpdateTime;
    }
    public String getOther1() {
        return other1;
    }

    public void setOther1(String other1) {
        this.other1 = other1;
    }
    public String getOther2() {
        return other2;
    }

    public void setOther2(String other2) {
        this.other2 = other2;
    }

    @Override
    public String toString() {
        return "Food{" +
            "foodId=" + foodId +
            ", foodName=" + foodName +
            ", foodPrice=" + foodPrice +
            ", foodScore=" + foodScore +
            ", foodDetail=" + foodDetail +
            ", foodType=" + foodType +
            ", foodMainImg=" + foodMainImg +
            ", foodRecommendStatus=" + foodRecommendStatus +
            ", foodCteateTime=" + foodCteateTime +
            ", foodUpdateTime=" + foodUpdateTime +
            ", other1=" + other1 +
            ", other2=" + other2 +
        "}";
    }
}


JwtInterceptor.java


package com.example.interceptor;

import com.example.util.JwtUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录检查拦截器
 * 被拦截下来的URL:
 * 1.获得token
 * 2.check token
 */
public class JwtInterceptor implements HandlerInterceptor {

    //在访问前拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("登录检查拦截器正在拦截URL>>>"+request.getRequestURI());
        //跨域请求会首先发一个option请求,直接返回正常状态并放行
        //if(request.getMethod().equals("OPTION"))
            //return true;
        //1.获得token
        String token = request.getHeader("token");
        if(token == null || token.equals("")){
            System.out.println("登录检查拦截器正在拦截,没有获得到token");
            //跳转到登录页面
            response.sendRedirect(request.getContextPath()+"/static/login.html");
            return false;
        }else {//2.check token
            System.out.println("登录检查拦截器正在拦截,获得到的token:"+token);
            if (JwtUtil.checkToken(token)){//有效token
                return true;
            }else {
                System.out.println("被拦截了,无效token");
                return false;
            }
        }

//        if(token != null){
//            if(JwtUtil.checkToken(token))
//                return true;//token有效
//        }
//        return false;

    }


}




FoodMapper.java


package com.example.mapper;

import com.example.entity.Food;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author dd
 * @since 2024-04-20
 */
public interface FoodMapper extends BaseMapper<Food> {

}




IFoodService.java


package com.example.service;

import com.example.entity.Food;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author dd
 * @since 2024-04-20
 */
public interface IFoodService extends IService<Food> {

    //评分排名前8的食物
    public List<Food> getHotFood();

}




FoodServiceImpl.java


package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Food;
import com.example.mapper.FoodMapper;
import com.example.service.IFoodService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author dd
 * @since 2024-04-20
 */
@Service
public class FoodServiceImpl extends ServiceImpl<FoodMapper, Food> implements IFoodService {

    @Autowired
    private FoodMapper foodMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public List<Food> getHotFood(){

        ListOperations<String,Food> operations =  redisTemplate.opsForList();
        // hotFood(K) - (V)
        String key = "hotFood";

        if (redisTemplate.hasKey(key)){//直接从缓存中返回
            List<Food> hotFoodList = operations.range(key,0,7);
            return hotFoodList;


        }else{//从数据库查询一份,放到Redis缓存中
            QueryWrapper<Food> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByDesc("food_score");

            Page<Food> page = new Page<>(1,8);
            page = foodMapper.selectPage(page,queryWrapper);
            List<Food> hotProductList =  page.getRecords();
            operations.leftPushAll(key,hotProductList);
            redisTemplate.expire(key,30, TimeUnit.SECONDS);// 30s过期,过期后Redis中没有了,则需要重新到MySQL中获得最新的数据
            return hotProductList;

        }

    }




}






JwtUtil.java


package com.example.util;


import com.example.entity.LoginCustomer;
import io.jsonwebtoken.*;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {

    private static final String jwtToken = "dahkgag7*$";
    private static long expireTime = 1000*60*60*24;



    /**
     * 创建新token
     * @param customerId 用户id
     * @param customerName
     * @return
     */
    public static String createToken(Integer customerId,String customerName){

        Map<String,Object> claims = new HashMap<>();
        claims.put("customerId",customerId);
        claims.put("customerName",customerName);

        System.out.println("创建token"+customerId);
        System.out.println("创建token"+customerName);

        JwtBuilder jwtBuilder = Jwts.builder().signWith(SignatureAlgorithm.HS256,jwtToken)//签发算法(head部分),秘钥为jwtToken
                .setClaims(claims)//body数据,要唯一,自行设。payload部分数据 //1.(customerId,customerName)--token
                .setIssuedAt(new Date())//设置签发时间:保证每次生成的token不同
                .setExpiration(new Date(System.currentTimeMillis()+expireTime));//一天的有效时间

        String token = jwtBuilder.compact();


        return token;
    }

    //验证token是否有效

    /**
     * 验证token是否有效
     * @param token 客户端携带的token
     * @return 返回是否有效
     */
    //2.验证token是否过期
    public static boolean checkToken(String token){
        if(token != null && !token.equals("")){
            try {
                Jwt parse = Jwts.parser().setSigningKey(jwtToken).parseClaimsJws(token);
                return true;
            }catch (ExpiredJwtException e){
                System.out.println("token已经过期了");
                return false;
            } catch (Exception e) {
                System.out.println("无效的token");
                return false;
            }
        }else
            return false;
    }




    /**
     * 解析token中的用户数据
     * @param token 客户端携带的token
     * @return 返回登录用户信息(customerIs)
     */
    public static LoginCustomer parseToken(String token){

        if(token != null && !token.equals("")) {
            try {
                Jwt parse = Jwts.parser().setSigningKey(jwtToken).parseClaimsJws(token);
                Map<String,Object> map = (Map<String, Object>)parse.getBody();
                if(map != null){
                    Integer custId = (Integer)map.get("customerId");//注意,此处的key 要与当初绑定进去的key一致
                    String custName = (String)map.get("customerName");//注意,此处的key 要与当初绑定进去的key一致

                    LoginCustomer loginCustomer = new LoginCustomer(custId,custName);
                    System.out.println("获得到的登录用户的信息是:" + loginCustomer);
                    return loginCustomer;
                }else{
                    System.out.println("获得到的登录用户的信息失败");
                    return null;
                }
            } catch (Exception e){
                e.printStackTrace();
                return null;
            }


        }else
            return null;

    }





}




ServerResult.java


package com.example.util;

public class ServerResult {
    private int code;
    private String msg;

    private Object data;



    public static ServerResult getSuccess(Object data){
        return new ServerResult(200,"查询成功",data);
    }

    public static ServerResult getFail(Object data){
        return new ServerResult(201,"查询失败",data);
    }


    /**
     * 添加、删除、修改的成功
     * @param data
     * @return
     */

    public static ServerResult updateSuccess(Object data){
        return new ServerResult(200,"处理成功",data);
    }


    /**
     * 添加、删除、修改的失败
     * @param data
     * @return
     */
    public static ServerResult updateFail(Object data){
        return new ServerResult(201,"处理失败",data);
    }


    public static ServerResult loginSuccess(Object data){
        return new ServerResult(200,"登录成功",data);
    }

    public static ServerResult loginFail(Object data){
        return new ServerResult(201,"登录失败",data);
    }






    public ServerResult() {
    }


    public ServerResult(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }


    @Override
    public String toString() {
        return "ServerResult{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}




ServletInitializer.java


package com.example;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringbootLoginApplication.class);
    }

}




SpringbootLoginApplication.java


package com.example;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@MapperScan("com.example.mapper")
@EnableCaching
public class SpringbootLoginApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootLoginApplication.class, args);
    }

}




food.sql


-- ----------------------------
-- Table structure for food
-- ----------------------------
DROP TABLE IF EXISTS `food`;
CREATE TABLE `food`  (
                         `food_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '美食id',
                         `food_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食名',
                         `food_price` decimal(10, 1) NULL DEFAULT NULL COMMENT '美食价格',
                         `food_score` float NULL DEFAULT NULL COMMENT '美食评分',
                         `food_detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食详情',
                         `food_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食类型',
                         `food_main_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食图片',
                         `food_recommend_status` int(0) NULL DEFAULT 0 COMMENT '美食推荐状态',
                         `food_cteate_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
                         `food_update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
                         `other1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
                         `other2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
                         PRIMARY KEY (`food_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 65 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of food
-- ----------------------------
INSERT INTO `food` VALUES (1, '奥尔良翅中', 56.5, 8.31, '翅中5个', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (2, '薄切猪梅花', 54.9, 6.64, '一斤', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (3, '金针菇', 39.4, 8.08, '金针菇', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (4, '私房炸小排', 44.3, 4.66, '油炸', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (5, '荞麦冷面', 59.1, 4.3, '荞麦', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (6, '五花肉', 41.6, 7.99, '五花肉', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (7, '雪花牛里脊', 59.9, 8.34, '牛里脊', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (8, '雪花香翁牛排', 87.1, 3.91, '新鲜牛排', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (9, '粉丝金针菇', 50.3, 8.59, '粉丝金针菇', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (10, '黑椒牛肉粒', 68.0, 3.63, '黑椒牛肉粒', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (11, '香辣鸡腿肉', 77.2, 5.53, '香辣鸡腿肉', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (12, '原切烧汁牛五花', 76.1, 4.07, '原切烧汁牛五花', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (13, '牛肋条', 66.7, 6.82, '牛肋条', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (14, '牛肉五花', 61.8, 5.49, '牛肉', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (15, '猪肉五花', 77.4, 7.32, '猪肉', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (16, '鱼豆腐', 84.7, 8.6, '鱼豆腐', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (17, '德州BBQ烤翅', 30.7, 8.75, '三件套', '汉堡', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (18, '黑松露菌菇和牛堡', 55.5, 8.26, '四件套', '汉堡', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (19, '美式卡真烤去骨鸡腿全餐', 85.2, 9.22, '单个', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (20, '招牌芝士和牛汉堡', 52.8, 7.53, '咖啡', '汉堡', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (21, '茴香小油条', 74.6, 7.9, '茴香小油条', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (22, '内蒙草原羔羊', 69.9, 3.3, '羊肉', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (23, '现炸小酥肉', 67.9, 8, '现炸', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (24, '雪花牛肉', 57.6, 8.68, '牛肉', '火锅', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (25, '炸豆皮', 77.5, 3.76, '放学小肉', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (26, '干贝咸蛋黄虾滑', 42.0, 5.41, '蛋黄虾滑', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (27, '老哥酥肉', 77.5, 9.08, '酥肉', '火锅', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (28, '雪花牛肉', 64.3, 5.42, '毛肚', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (29, '风花雪月', 83.2, 3.22, '风花雪月', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (30, '黑牛牡蛎肉', 78.6, 7.09, '黑牛牡蛎肉', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (31, '青海烤饼', 63.7, 8.19, '饼1个', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (32, '黑牛肋条', 61.4, 9.63, '黑牛肋条', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (33, '大片毛肚', 40.2, 9.92, '大片毛肚', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (34, '灯影鱼片', 62.6, 6.72, '鱼片', '火锅', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (35, '飞鱼籽虾滑', 66.7, 9.8, '虾滑', '火锅', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (36, '牛舌', 78.9, 3.46, '牛舌', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (37, '迷你汉堡', 53.8, 5.42, '会员专享', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (38, '蘑菇味狠浓牛肉汉堡', 71.8, 6.35, '单人餐', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (39, '四重芝士狠浓牛肉汉堡', 51.6, 3.37, '单人下午茶', '汉堡', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (40, 'M8澳洲和牛', 64.1, 8.5, '澳洲和牛', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (41, 'M5牛肉', 81.0, 7.85, '牛肉', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (42, '海鲜拼盘', 59.0, 8.94, '海鲜拼盘', '火锅', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (43, '鱼籽鲜虾滑', 40.5, 4.57, '虾滑', '火锅', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (44, '加州汉堡套餐', 43.1, 4.37, '兑换券', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (45, '双层美式汉堡', 88.9, 8.74, '兑换券', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (46, '招牌安格斯牛肉汉堡单人餐', 35.0, 6.97, '兑换券', '汉堡', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (47, '孜然鸡肉条', 82.6, 5.25, '兑换券', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (48, '上等黑虎虾', 56.7, 9.95, '虾', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (49, '上等牛五花', 85.7, 6.99, '牛五花', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (50, '土豆泥', 50.5, 5.52, '土豆泥', '烤肉', '', 1, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (52, '现切冰鲜牛排', 53.4, 4, '现切冰鲜牛排', '烤肉', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (53, '超传统超级棒约翰', 43.0, 5.33, '超传统超级棒约翰', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (54, '榴莲芝士条', 54.3, 7.11, '榴莲芝士条', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (55, '洋葱圈', 55.0, 8.2, '洋葱圈', '汉堡', '', 0, NULL, NULL, NULL, NULL);
INSERT INTO `food` VALUES (56, '意式红烩牛肉焗饭', 40.0, 5.44, '意式红烩牛肉焗饭', '汉堡', '', 0, NULL, NULL, NULL, NULL);




FoodMapper.xml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.FoodMapper">

</mapper>




application.yaml


server:
  servlet:
    context-path: /app
  port: 80

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dicts?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  redis:
    host: localhost
    port: 6379
    database: 0
    connect-timeout: 1800000
  mvc:
    view:
      prefix: / #前缀
      suffix: .jsp #后缀
    hiddenmethod:
      filter:
        enabled: true # 支持表单 method 转换

logging:
  file:
    path: d://logger #日志记录
  level:
    com.example: debug





css_04_首页.css


*{
    margin: 0;
    padding: 0;
}
/* =======================头部======================= */
.header{
    width: 85%;   /*  %: 父元素(父标签的百分比)*/
    height: 58px;
    /* background-color: aquamarine; */
    min-width: 1000px;
    margin: 0 auto;  /*容器水平居中*/
}

/* =======================logo部分 =======================*/
.header .logo{
    width: 15%;
    height: 33px;
    /* background-color: #fa8072; */
    float: left;   /*不换行*/
    margin-top: 12px;  /*距离顶部间距*/
}

.header .logo a{  /*行内元素不能设置宽高度,转换成 inline-block / block*/
    display: inline-block;
    width: 100%;
    height: 33px;
    background: url(../images/header-small-sprites3.png) no-repeat 0 -25px;
    background-size: 125px;
}




/*======================= 导航部分 =======================*/
.header .nav{
    width: 35%;
    height: 100%;
    /* background-color: skyblue; */
    float: left;
    min-width: 450px;
}

/* 1.设置UL 宽高度 : 100%
2.小黑点去掉UL
3.Li 不换行 : float :left 
4.设置每个li 宽高度
5.A 超链接宽高度 = li 宽高度
6.设置a超链接文字的大小,居中,下划线
7.鼠标悬浮样式修改 a:hover */

.nav .head-nav{
  width: 100%;
  height: 100%;
  /* background-color: burlywood; */
  list-style: none;  /*小黑点去掉UL*/
}

.head-nav li{
    float: left;  /*不换行 */
    height: 100%;
    width: 80px;
   /* border-right: 1px dotted white;  solid : 实线 , dashed: 虚线 , dotted : 圆点*/
}

.head-nav li a{
    display: inline-block;
    width: 100%;
    height: 100%;
    color: rgb(78, 78, 78);
    text-decoration: none; /*超链接下划线去除*/
    font-size: 13px;
    text-align: center;
    line-height: 58px;
}
.head-nav li a:hover{  /*鼠标悬浮样式修改 */
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
    border-bottom: 3px solid rgba(230, 69, 102, 0.1)
}

.head-nav .first-item{  /*第一个li ,首页*/
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
}
.head-nav .first-item:hover{ /*第一个li ,首页,鼠标悬浮不变*/
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
    border-bottom:none;
}


/* =====================搜索区域=========================== */
.search{
    width: 25%;
    height: 100%;
      /* background-color: yellow;  */
    float: left;
    min-width: 260px;
}


.search form{
    width: 100%;
    height: 30px;
    /* background-color: aqua; */
    margin-top: 12px;
   
}
/* 搜索框 */
.search form .search-kw{
    width: 180px;
    height: 100%;
    border: 1px solid rgba(230, 69, 102, 0.1);
    border-radius: 4px;
   outline: none; /*点击输入框的内边框 取消*/
   padding-left: 10px;/*内部的文字 左间距 : 左内间距*/
   color:  rgb(108, 108, 108);
}

/* 搜索按钮 */
.search .search-btn{
    width: 60px;
    height: 30px;
    background-color: rgba(230, 69, 102, 0.1);
    font-size: 12px;
    color: rgb(78, 78, 78);
    border: none;
    cursor: pointer ;  /*鼠标悬浮上去 是小手链接形状*/
    border-radius: 4px;
}

/*======================= 登录区域======================= */
.header  .login{
    
    width: 13%;
    height: 100%;
    /* background-color: yellow; */
    float: right;
}

.login a{
    display: inline-block;
    width: 60px;
    height: 30px;
    background-color: rgba(230, 69, 102, 0.1);
    margin-top: 14px;  /*上间距*/
    border-radius: 4px;  /*圆角*/
    text-decoration: none;
    color: rgb(78, 78, 78);
    font-size: 12px;
    text-align: center;
    line-height: 30px;
}

.login a:hover{  /*:hover  鼠标悬浮*/
    /* background-color:white;
    color: rgba(230, 69, 102, 0.1); */
    /* border: 1px solid rgba(230, 69, 102, 0.1); */
    font-weight: bold;
}


/* ==========================banner======================== */
.banner{
    width: 100%;
    height: 400px;
    /* background-color: salmon; */
}

.banner img{
    width: 100%;
    height: 100%;
}

/*    =======================  热门商品==================  */
.pro-title{
    width: 100%;
    height: 80px;
    /* background-color: salmon; */
    text-align: center;
    line-height: 80px;
    font-size: 28px;
}
/* 商品列表 */
.pro-list{
    width: 85%;
    height: 660px;
    /* background-color: skyblue;  */
   margin:  0 auto; /* 容器居中 */
}

.pro-list ul{
    width: 100%;
    height:  100%;
    list-style: none;
}

.pro-list ul li{
    width: 230px;
    height: 320px;
    /* border: 3px solid salmon; */
    float: left;  /* 不换行 */
    margin-right: 30px;
    margin-bottom: 10px;

}

.pro-list ul li img{
    width: 160px;
    height: 160px;
    /* background-color: sandybrown; */
}

.pro-list ul  .pro-name{
    width: 190px;
    height: 48px;
    /* background-color: chartreuse; */
    margin-left: 20px;
    font-size: 13px;
    color: darkgrey;
    text-align: center;
}
.pro-name-a{
    text-decoration: none;
}
.pro-list ul  .pro-price{
    width: 190px;
    height: 18px;
    /* background-color: antiquewhite; */
    margin-left: 20px;
    margin-top: 10px;
    text-align: center;
    color: rgba(230, 69, 101, 0.591);

}

.pro-price i{
    vertical-align: middle;
    font-size: 12px;
    font-weight: 700;
    font-family: MicrosoftYahei-regular,Arial,Helvetica,sans-serif;
}



index.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>首页</title>
    <link href="css/css_04_首页.css" rel="stylesheet"/>
    <link rel="shortcut icon" href="images/favicon.ico" />

    <script src="js/jquery-3.7.0.min.js"></script>







</head>
<body>
<!-- ======================1. 头部 ======================-->
<div class="header">
    <div class="logo">
        <a href=""> </a>
    </div>

    <div class="nav">
        <ul class="head-nav">
            <li><a href="" class="first-item">首页</a></li>
            <li><a href="">菜品</a></li>
            <li><a href="">店铺</a></li>
            <li><a href="">热卖</a></li>
            <li><a href="">优惠券</a></li>

        </ul>
    </div>

    <div class="search">
        <form>
            <input type="text" class="search-kw" >
            <input type="submit" class="search-btn" value="搜索"/>
        </form>
    </div>
    <div class="login">
        <a href="login.html">登录</a>
        <a href="">注册</a>
    </div>
</div>

<!-- ======================2. 横幅 banner ======================-->
<div class="banner">
    <img src="images/bg1.jpg" />
</div>


<!-- =======================3. 热门商品================== -->
<h3 class="pro-title"> 热门商品</h3>
<div class="pro-list">
    <ul>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>


    </ul>
</div>





<script>











    function loadIndexInfo() {
        let token = localStorage.getItem("token");
        console.log(token);
        let url = "http://localhost:80/app/food/hot";

        document.addEventListener('DOMContentLoaded', function() {
            $.ajax({
                type: "get",
                url: url,
                //headers: {'token': token},
                success: function(result) {
                    console.log(result);
                    if (result.code == 200) {
                        // 使用querySelectorAll来选择所有class为'pro-img'的元素
                        var imgElements = document.querySelectorAll('.pro-img');
                        console.log(imgElements.length);



                        // 确保有足够的数据和图片元素
                        var minLength = Math.min(result.data.length, imgElements.length);
                        for (var i = 0; i < minLength && i < 8; i++) { // 只给前8个元素赋值
                            imgElements[i].src = result.data[i].foodMainImg;
                            console.log('Updated image element #' + (i + 1) + ' with URL: ' + result.data[i].foodMainImg);
                        }

                        // 如果数据不足8条或者图片元素不足8个,打印警告信息
                        if (minLength < 8 || result.data.length < 8) {
                            console.warn('Not enough data or image elements to assign to 8 images.');
                        }
                    } else {
                        // 添加错误处理逻辑,例如:
                        console.error('Request failed with code:', result.code);
                    }


                }

            });
        });
    }

    // 调用函数加载信息
    loadIndexInfo();




</script>










</body>
</html>



pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>





    <artifactId>springboot_login</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>springboot_login</name>
    <description>springboot_login</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>




    <dependencies>

        <!--引入redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.0</version>
        </dependency>











        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>




        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generate -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>





  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简 洁 冬冬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值