Commit f21ddbd9 by Patryk Czarnik

uzupełnienia, inne wersje itp

parent 001e3c7f
Aby nie mieszać w projekcie, różne "alternatywne podejścia" do koszyka i sesji zapiszę w pliku tekstowym.
1) Wstrzyknięcie HttpSession z serwletów (ewentualnie można też HttpServletRequest i z niego pobrać)
@GetMapping("/{id}/add-to-basket")
public String addToBasket(Model model,
@PathVariable("id") Integer productId,
HttpSession httpSession) {
Optional<Product> maybeProduct = repository.findById(productId);
if(maybeProduct.isPresent()) {
Basket basket = (Basket) httpSession.getAttribute("basket");
if(basket == null) {
basket = new Basket();
httpSession.setAttribute("basket", basket);
}
basket.incrementProduct(maybeProduct.get());
}
return "redirect:/products";
}
2) Analogiczne możliwości daje WebRequest ze springa
@GetMapping("/{id}/add-to-basket")
public String addToBasket(Model model,
@PathVariable("id") Integer productId,
WebRequest webRequest
) {
Optional<Product> maybeProduct = repository.findById(productId);
if(maybeProduct.isPresent()) {
Basket basket = (Basket) webRequest.getAttribute("basket", WebRequest.SCOPE_SESSION);
if(basket == null) {
basket = new Basket();
webRequest.setAttribute("basket", basket, WebRequest.SCOPE_SESSION);
}
basket.incrementProduct(maybeProduct.get());
}
return "redirect:/products";
}
3) Zamiast if(basket == null), można zdefiniować @Bean-a typu HttpSessionListener (jak w technologii serwletów)
i w nim zainicjować sesję. Do inicjalizacji dojdzie, gdy jakaś pierwsza metoda wstrzyknie sobie HttpSession lub w inny sposó” odwoła się do sesji.
@Configuration
public class BasketConfiguration {
@Bean
public HttpSessionListener createSessionListener() {
return new HttpSessionListener() {
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("tworzę sesję nr " + session.getId());
session.setAttribute("basket", new Basket());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("koniec sesji nr " + session.getId());
}
};
}
}
a w kontrolerze:
@GetMapping("/{id}/add-to-basket")
public String addToBasket(Model model,
@PathVariable("id") Integer productId,
HttpSession session) {
Optional<Product> maybeProduct = repository.findById(productId);
if(maybeProduct.isPresent()) {
Basket basket = (Basket) session.getAttribute("basket");
basket.incrementProduct(maybeProduct.get());
}
return "redirect:/products";
}
4) Ta wersja zostaje w projekcie za stałe.
Obiekt z sesji można wstrzyknąć bezpośrednio jako parametr, używając @SessionAttribute.
Niestety, samo użycie tej adnotacji nie wyzwala inicjalizacji sesji opisanej w punkcie 3),
daje tylko dostęp do atrybutu sesji jeśli on już wcześniej istnieje.
W przypadku naszej aplikacji sesja inicjalizuje się, gdy wyświetlana jest główna strona z produktami (w zasadzie dokonuje tego JSP),
ale czasami może być konieczne dodanie parametru HttpSession do metody, tylko po to, aby wymusić inicjalizcję sesji.
@GetMapping("/{id}/add-to-basket")
public String addToBasket(Model model,
@PathVariable("id") Integer productId,
@SessionAttribute Basket basket) {
Optional<Product> maybeProduct = repository.findById(productId);
if(maybeProduct.isPresent()) {
basket.incrementProduct(maybeProduct.get());
}
return "redirect:/products";
}
5) Alternatywnie można zdefiniować "bean-a w zakresie sesji" i wstrzyknąć do w kontrolerze za pomocą @Autowired.
Jeśli w miejscu wstrzyknięcia używamy nazwy klasy (a nie interfejsu), to należy dodatkowo ustawić proxy na "target class". W innych sytuacjach mogą działać inne opcje.
@Component
@Scope(scopeName="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class BasketBean {
private Map<Integer, ProductInBasket> products = new TreeMap<>();
public Collection<ProductInBasket> getProducts() {
return Collections.unmodifiableCollection(products.values());
}
public void incrementProduct(Product product) {
if(products.containsKey(product.getProductId())) {
ProductInBasket pib = products.get(product.getProductId());
pib.increment(1);
} else {
ProductInBasket pib = new ProductInBasket();
pib.setProductId(product.getProductId());
pib.setName(product.getName());
pib.setPrice(product.getPrice());
pib.setCount(1);
products.put(pib.getProductId(), pib);
}
}
public BigDecimal getBasketValue() {
return products.values().stream()
.map(ProductInBasket::getValue)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
a w kontrolerze:
@Autowired
private BasketBean basket;
@GetMapping
public String allProducts(Model model) {
List<Product> products = repository.findAll();
model.addAttribute("products", products);
model.addAttribute("basket", basket); // !!!
return "products";
}
@GetMapping("/{id}/add-to-basket")
public String addToBasket(@PathVariable("id") Integer productId) {
Optional<Product> maybeProduct = repository.findById(productId);
if(maybeProduct.isPresent()) {
basket.incrementProduct(maybeProduct.get());
}
return "redirect:/products";
}
\ No newline at end of file
package com.example.demo.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.antMatchers("/products/new", "/products/*/edit").hasAuthority("ROLE_manager") // tylko manager może edytować
.antMatchers("/customers/new", "/customers/*/edit").hasAuthority("ROLE_manager")
.antMatchers("/products/find").authenticated() // zalogowany jako ktokolwiek może wyszukiwać
.antMatchers("/", "/whoami", "/products/**", "/customers/**", "/*.css").permitAll() // dostęp dla wszystkich
.antMatchers("/products?", "/products?/**").permitAll() // inne wersje listy produktów
.antMatchers("/rest/**").permitAll()
// .antMatchers("/login").anonymous() // nie może być zalogowany! - ale to przestało działać...
.antMatchers("/login").permitAll()
.antMatchers("/logout").authenticated() // zalogowany jako ktokolwiek
.anyRequest().denyAll() // pozostałe adresy blokujemy
.and()
.formLogin()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder)
.usersByUsernameQuery("SELECT username, password, enabled FROM spring_accounts WHERE username = ?")
.authoritiesByUsernameQuery("SELECT username, role FROM spring_account_roles WHERE username = ?");
// wersja inMemory:
// auth.inMemoryAuthentication()
// .withUser("ala").password("{noop}abc123").roles("manager", "sprzedawca")
// .and()
// .withUser("ola").password("{noop}abc123").roles("sprzedawca")
// .and()
// .withUser("ula").password("{noop}abc123").roles();
}
}
......@@ -41,5 +41,14 @@
<li><a href="/customers/ala@example.com/edit">edycja klienta</a>
</ul>
<h2>Alternatywne dostępy do bazy danych</h2>
<ul>
<li><a href="/alt1/products">Dostęp JDBC</a> (klasyczne getConnection)</li>
<li><a href="/alt1/products/1">jeden produkt</a></li>
<li><a href="/alt1/products/szukaj?name=pralka">wg nazwy</a></li>
<li><a href="/alt2/products">Dostęp JDBC</a> (wstrzykiwanie DataSource)</li>
<li><a href="/alt2/products/1">jeden produkt</a></li>
<li><a href="/alt2/products/szukaj?name=pralka">wg nazwy</a></li>
</ul>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment