Хранение состояния в контроллере в Spring - PullRequest
0 голосов
/ 30 августа 2018

Ищу несколько советов, пытаюсь сделать карточную игру. Я - полный новичок в Spring MVC (если следующий вопрос уже не дает ответа ...)

При использовании компонента Bean в прокси-сеансе для управления состоянием игры мои маршруты работают правильно с помощью Postman и могут создать нового игрока.

Игровой класс

@Component
public class Game {
private Deck deck;
private ArrayList<Player> players;
private HashMap<Player, Integer> wins;

@Autowired
public Game(Deck deck){
    this.deck = deck;
    this.players = new ArrayList<>();
    this.wins = new HashMap<>();
}

public ArrayList<Player> getPlayers() {
    return players;
}

public void addPlayer(String name){
    this.players.add(new Player(name));

ApplicationConfig class

@EnableWebMvc
@Configuration
@ComponentScan("com.kane.cardgame")
public class ApplicationConfig {
  private Deck deck = new Deck();

  @Bean
  @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = 
  ScopedProxyMode.TARGET_CLASS)
  public Game game(){
    return new Game(deck);
  }
}

Контроллер

@CrossOrigin
@RestController(value="PlayerController")
@RequestMapping("/game/players")
public class PlayerController {
  @Autowired
  private Game game;

  @RequestMapping(method=RequestMethod.GET, value="/")
  public ArrayList<Player> allPlayers(){
    return game.getPlayers();
  }

  @RequestMapping(method= RequestMethod.POST, value="/")
  public ArrayList<Player> addPlayer(@RequestParam(value="name") String 
  name){
    game.addPlayer(name);
    return game.getPlayers();
  }

Реагировать Компонент, который делает запрос

const handleLinkClick = e => {
const url = `http://localhost:8080/game/players/? 
name=${this.state.name}`
  fetch(url, {
    method: 'POST',
    mode: 'cors'
  })
  .then(res => res.json())
  .then(res => {
    const newState = this.state.newPlayers;
    newState.push(res);
    this.setState({newPlayers: newState})
  })
 }

 return(
 <div>
   <h1>Enter your name</h1>
   <input id="name-input" type="text" name="name" onChange= . 
   {handleNameChange}/>
   <Link to="/newPlayer" onClick={handleLinkClick}>Start Game</Link>
  </div>
  )

Когда я делаю эти запросы в Почтальоне, все в порядке. Он работает как надо - после запуска маршрута и добавляется новый игрок, а когда я запускаю маршрут Get, он возвращает всех игроков с добавленным новым.

Когда я использую React для выполнения этого запроса, создается впечатление, что создается экземпляр моего класса Player (поскольку идентификатор увеличивается), но, похоже, он не добавляет игрока в ArrayList, содержащийся в игре. Я могу заставить его вернуть Player, который он только что создал как JSON, и сохранить его в состоянии. Но когда я получаю URL-адрес, связанный с маршрутом получения, чтобы вернуть игроков в игре, они не сохраняются. Я догадываюсь, что я не храню это состояние игры должным образом.

Я предполагаю, что это , вероятно, сводится к фундаментальному недоразумению о том, как работает этот Бин. Любой совет будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Хорошо, здесь идет,

Здесь есть несколько вещей, которые не в порядке. Сначала давайте начнем с класса Game. Это помечено @Component. Это означает, что автоматическое сканирование пути к классам в Spring с помощью этого параметра автоматически настраивается. С учетом вышесказанного вам будет легко сделать инъекцию, когда вам это нужно. В то же время это означает, что ручная установка в классе ApplicationConfig не требуется. Там вы вручную создаете экземпляр Game и пытаетесь перевести его в контекст Spring с аннотацией @Bean. Это неправильно и может привести к неожиданным результатам. Либо держите класс @Component, либо другой.

Во-вторых, Game на самом деле является сервисным компонентом, который управляет всей игрой. Имея это в виду, я бы предложил удалить @Component и добавить аннотацию @Service, чтобы лучше обозначить его фактическое использование (в конце концов, это услуга). Аннотация @Autowired к его конструктору также не нужна, поскольку вы не можете эффективно вводить туда управляемые компоненты Spring. Вместо этого, если вы хотите выполнить действия по созданию бина (т.е. инициализировать объект Deck и различные списки и карты), просто создайте новый метод void и добавьте к нему аннотацию @PostConstruct. Несмотря на это, обязательно измените эти объявления с private ArrayList<Player> players; на private List<Player> players;, так как всегда лучше кодировать интерфейс, чем фактическая реализация. То же самое относится к аргументу возврата getPlayers.

Наконец, когда все это на месте, просто внедрите класс Game в свой PlayerController (также убедитесь, что вы делаете это с использованием предпочтительного метода DI, основанного на конструкторе), и вам будет хорошо.

Наконец, я предлагаю вам ознакомиться с тем, как работает Spring и вообще DI, прежде чем продолжить, в противном случае у вас возникнут проблемы.

Редактировать: также, как упоминалось в ответе выше, изменения на стороне клиента также должны иметь место.

0 голосов
/ 31 августа 2018

Измените @RequestParam на @RequestBody и попробуйте использовать что-то вроде этого

fetch('http://localhost:8080/game/players/', {
    method: 'POST',
    mode: 'cors'
},
body: JSON.stringify({
    name: ${this.state.name},
})
)
.then(res => res.json())
.then(res => {
    const newState = this.state.newPlayers;
    newState.push(res);
    this.setState({newPlayers: newState})
})
...