1.Order类缺少tacos属性和addDesign方法

代码如下:

package tacos;

import lombok.Data;
import org.hibernate.validator.constraints.CreditCardNumber;

import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.util.ArrayList;
import java.util.Date;


@Data
public class Order {
    private Long id;
    private Date placedAt;
    private ArrayList<Taco> tacos = new ArrayList<>();

    public void addDesign(Taco design) {
        this.tacos.add(design);
    }

    @NotBlank(message = "Name is required")
    private String name;
    @NotBlank(message = "Street is required")
    private String street;
    @NotBlank(message = "City is required")
    private String city;
    @NotBlank(message = "State is required")
    private String state;
    @NotBlank(message = "Zip code is required")
    private String zip;
    @CreditCardNumber(message = "Not a valid credit card number")
    private String ccNumber;
    @Pattern(regexp = "^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",message = "Must be formatted MM/YY")
    private String ccExpiration;
    @Digits(integer = 3,fraction = 0,message = "Invalid CVV")
    private String ccCVV;
}

2.数据库字段名与Order类属性不相同

因为代码用了ObjectMapper及其convertValue()方法了,所以要求Order属性名和对应数据库表列名相同。但之前的sql文件创建order表没做到这一点。应如下:

create table if not exists Taco_Order(
    id identity,
    name varchar(50) not null,
    street varchar(50) not null,
    city varchar(50) not null,
    state varchar(2) not null,
    zip varchar(10) not null,
    ccNumber varchar(16) not null,
    ccExpiration varchar(5) not null,
    ccCVV varchar(3) not null,
    placedAt timestamp not null
);

3.JdbcTacoRepository的keyHolder.getKey().longValue()空指针问题

要加一句:preparedStatementCreatorFactory.setReturnGeneratedKeys(true);
代码如下:

package tacos.data;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import tacos.Ingredient;
import tacos.Taco;


import java.sql.*;
import java.util.Arrays;
import java.util.Date;


@Repository
public class JdbcTacoRepository implements TacoRepository {
    private JdbcTemplate jdbc;

    @Autowired
    public JdbcTacoRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    @Override
    public Taco save(Taco taco) {
        long tacoId = saveTacoInfo(taco);
        taco.setId(tacoId);
        for (Ingredient ingredient : taco.getIngredients()) {
            saveIngredientToTaco(ingredient, tacoId);
        }
        return taco;
    }

    private long saveTacoInfo(Taco taco) {
        taco.setCreatedAt(new Date());
        //下面这行原答案错误。
        //PreparedStatementCreator psc = new PreparedStatementCreatorFactory("insert into Taco (name, createdAt) values (?,?)", Types.VARCHAR, Types.TIMESTAMP).newPreparedStatementCreator(Arrays.asList(taco.getName(), new Timestamp(taco.getCreatedAt().getTime())));

        PreparedStatementCreatorFactory preparedStatementCreatorFactory =
                new PreparedStatementCreatorFactory(
                        "INSERT into Taco (name,createdAt) values (?,?)",
                        Types.VARCHAR,Types.TIMESTAMP
                );
        preparedStatementCreatorFactory.setReturnGeneratedKeys(true);       //不加这句话会导致keyHolder.getKey()获取不到id
        PreparedStatementCreator psc = preparedStatementCreatorFactory.newPreparedStatementCreator(
                Arrays.asList(
                        taco.getName(),
                        new Timestamp(taco.getCreatedAt().getTime())
                )
        );


        KeyHolder keyHolder=new GeneratedKeyHolder();
        jdbc.update(psc,keyHolder);
        return keyHolder.getKey().longValue();
    }

    private void saveIngredientToTaco(Ingredient ingredient ,long tacoId){
        jdbc.update("insert  into Taco_Ingredients (taco,ingredient)"+"values (?,?)",tacoId,ingredient.getId());
    }

}

4.Taco类getIngredients()返回值问题

因为在JdbcTacoRepository中是这么使用Taco类的getIngredients()方法的:for (Ingredient ingredient : taco.getIngredients())
所以要更改Taco类的属性:

private List<Ingredient> ingredients;

但与之而来的是页面与后端的转换问题。表单中的Ingredient都是String类型,而此时没有办法将String类型转化为Ingredient,需要配置Converter类将Sring转化为Ingredient类。
代码如下:

package tacos;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import tacos.data.IngredientRepository;

@Component
public class IngredientByIdConverter implements Converter<String, Ingredient> {

    private IngredientRepository ingredientRepo;

    @Autowired
    public IngredientByIdConverter(IngredientRepository ingredientRepo) {
        this.ingredientRepo = ingredientRepo;
    }

    @Override
    public Ingredient convert(String id) {
        return ingredientRepo.findOne(id);
    }
}

5.H2数据库的访问

启动程序后,用链接:http://localhost:8080/h2-console进行访问。
在程序的控制台日志中找到类似:
H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:0409e967-692c-4378-868e-d9790aeff5ca'的内容。
at后面引号中的名称即你此次运行创建的内存数据库,在h2-console中JDBC URL中填入此字符串,用户名密码都为默认(sa,空)并连接,即可访问数据库。
这种方式下,数据库名(JDBC URL)每次运行都会变动。
除此之外,还可以在application.properties中设置JDBC URL,账号,密码,驱动等。并用设置的信息进行登录。

6.其他

因为加了验证,所以信用卡要用正确的测试卡号,如:5105105105105100

验证错误时,在DesignTacoController的processDesign中直接放回“design”是无法加载配料数据的。这是小的错误。而且Taco的配料属性的检验长度不能为0也是无法生效的。

    @PostMapping
    public String processDesign(@Valid Taco design, Errors errors,@ModelAttribute Order order) {
        if (errors.hasErrors()) {
            return "design";        //太简单了,无法加载数据
        }
        Taco saved=designRepo.save(design);
        order.addDesign(saved);

        return "redirect:/orders/current";
    }
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐